@ttsc/lint 0.18.4 → 0.19.0

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.
Files changed (188) hide show
  1. package/README.md +95 -43
  2. package/go.mod +5 -4
  3. package/internal/rulecode/rulecode.go +88 -0
  4. package/lib/index.d.ts +10 -1
  5. package/lib/index.js +45 -17
  6. package/lib/index.js.map +1 -1
  7. package/lib/structures/ITtscLintConfig.d.ts +3 -0
  8. package/lib/structures/TtscLintRuleSetting.d.ts +3 -2
  9. package/lib/structures/format/ITtscLintFormat.d.ts +3 -2
  10. package/lib/structures/format/ITtscLintFormatSortImports.d.ts +20 -4
  11. package/lib/structures/rules/ITtscLintBoundariesRuleOptions.d.ts +80 -8
  12. package/lib/structures/rules/ITtscLintBoundariesRules.d.ts +6 -8
  13. package/lib/structures/rules/ITtscLintContributorRules.d.ts +18 -2
  14. package/lib/structures/rules/ITtscLintCoreRuleOptions.d.ts +347 -0
  15. package/lib/structures/rules/ITtscLintCoreRuleOptions.js +3 -0
  16. package/lib/structures/rules/ITtscLintCoreRuleOptions.js.map +1 -0
  17. package/lib/structures/rules/ITtscLintCoreRules.d.ts +101 -67
  18. package/lib/structures/rules/ITtscLintRegexpRules.d.ts +7 -2
  19. package/lib/structures/rules/ITtscLintRuleOptionsMap.d.ts +53 -7
  20. package/lib/structures/rules/ITtscLintRules.d.ts +6 -2
  21. package/lib/structures/rules/ITtscLintSolidRules.d.ts +0 -8
  22. package/lib/structures/rules/ITtscLintTypeScriptRuleOptions.d.ts +206 -0
  23. package/lib/structures/rules/ITtscLintTypeScriptRuleOptions.js +8 -0
  24. package/lib/structures/rules/ITtscLintTypeScriptRuleOptions.js.map +1 -0
  25. package/lib/structures/rules/ITtscLintTypeScriptRules.d.ts +55 -42
  26. package/lib/structures/rules/ITtscLintUnicornRuleOptions.d.ts +276 -0
  27. package/lib/structures/rules/ITtscLintUnicornRuleOptions.js +3 -0
  28. package/lib/structures/rules/ITtscLintUnicornRuleOptions.js.map +1 -0
  29. package/lib/structures/rules/ITtscLintUnicornRules.d.ts +44 -36
  30. package/lib/structures/rules/index.d.ts +3 -0
  31. package/lib/structures/rules/index.js +3 -0
  32. package/lib/structures/rules/index.js.map +1 -1
  33. package/linthost/ast_helpers.go +521 -23
  34. package/linthost/ast_selector_matcher.go +1628 -0
  35. package/linthost/ast_selector_parser.go +628 -0
  36. package/linthost/comment_scan.go +154 -0
  37. package/linthost/compile.go +129 -79
  38. package/linthost/config.go +352 -88
  39. package/linthost/config_format.go +15 -1
  40. package/linthost/contrib_adapter.go +47 -8
  41. package/linthost/declaration_rules.go +12 -11
  42. package/linthost/directives.go +9 -67
  43. package/linthost/dispatch.go +37 -3
  44. package/linthost/engine.go +368 -53
  45. package/linthost/escape_string.go +77 -0
  46. package/linthost/fix.go +133 -23
  47. package/linthost/flags_gen.go +18 -17
  48. package/linthost/format.go +73 -167
  49. package/linthost/format_editor_settings.go +134 -26
  50. package/linthost/grapheme_tables_gen.go +1920 -0
  51. package/linthost/host.go +160 -61
  52. package/linthost/literal_escape_scan.go +117 -0
  53. package/linthost/lsp.go +545 -98
  54. package/linthost/numeric_literal_precision.go +228 -0
  55. package/linthost/polyfill_browserslist.go +1439 -0
  56. package/linthost/polyfill_browserslist_config.go +603 -0
  57. package/linthost/polyfill_corejs.go +750 -0
  58. package/linthost/polyfill_data.go +113 -0
  59. package/linthost/polyfill_data_gen.json +39868 -0
  60. package/linthost/print_nodes_array.go +7 -1
  61. package/linthost/print_nodes_object.go +7 -1
  62. package/linthost/project_engine.go +151 -0
  63. package/linthost/project_rules.go +78 -0
  64. package/linthost/regex_clean.go +191 -0
  65. package/linthost/regex_tree.go +1544 -0
  66. package/linthost/regex_tree_optimizer.go +1685 -0
  67. package/linthost/regexp_cache.go +44 -0
  68. package/linthost/rule_codes.go +105 -0
  69. package/linthost/rule_codes.json +745 -0
  70. package/linthost/rules_ban_ts_comment.go +312 -0
  71. package/linthost/rules_boundaries.go +128 -43
  72. package/linthost/rules_boundaries_dependencies.go +1013 -0
  73. package/linthost/rules_core_extra.go +62 -92
  74. package/linthost/rules_cypress.go +1 -1
  75. package/linthost/rules_default_case.go +87 -11
  76. package/linthost/rules_dupes.go +38 -13
  77. package/linthost/rules_empty.go +188 -20
  78. package/linthost/rules_escape.go +62 -48
  79. package/linthost/rules_format_arrow_parens.go +19 -5
  80. package/linthost/rules_format_bracket_spacing.go +1 -1
  81. package/linthost/rules_format_clause_join.go +1 -1
  82. package/linthost/rules_format_declaration_header.go +31 -19
  83. package/linthost/rules_format_indent.go +1 -1
  84. package/linthost/rules_format_jsdoc.go +1 -1
  85. package/linthost/rules_format_orphan_semi.go +1 -1
  86. package/linthost/rules_format_parameter_properties.go +17 -7
  87. package/linthost/rules_format_print_width.go +1 -1
  88. package/linthost/rules_format_quote_props.go +1 -1
  89. package/linthost/rules_format_quotes.go +1 -1
  90. package/linthost/rules_format_semi.go +106 -79
  91. package/linthost/rules_format_sort_imports.go +79 -45
  92. package/linthost/rules_format_statement_split.go +1 -1
  93. package/linthost/rules_format_ternary_nullish_parens.go +1 -1
  94. package/linthost/rules_format_trailing_comma.go +64 -1
  95. package/linthost/rules_format_whitespace.go +1 -1
  96. package/linthost/rules_functional.go +21 -22
  97. package/linthost/rules_gap.go +80 -3
  98. package/linthost/rules_grouped_accessor_pairs.go +84 -25
  99. package/linthost/rules_guard_for_in.go +64 -147
  100. package/linthost/rules_jsx_a11y.go +232 -22
  101. package/linthost/rules_logic.go +84 -38
  102. package/linthost/rules_nextjs.go +105 -16
  103. package/linthost/rules_no_class_assign.go +70 -0
  104. package/linthost/rules_no_duplicate_imports.go +266 -0
  105. package/linthost/rules_no_else_return.go +156 -38
  106. package/linthost/rules_no_extend_native.go +113 -17
  107. package/linthost/rules_no_fallthrough.go +1013 -0
  108. package/linthost/rules_no_func_assign.go +70 -0
  109. package/linthost/rules_no_import_assign.go +278 -86
  110. package/linthost/rules_no_inner_declarations.go +186 -0
  111. package/linthost/rules_no_loop_func.go +438 -53
  112. package/linthost/rules_no_mixed_operators.go +208 -52
  113. package/linthost/rules_no_param_reassign.go +376 -61
  114. package/linthost/rules_no_promise_executor_return.go +156 -0
  115. package/linthost/rules_no_restricted_imports.go +1013 -57
  116. package/linthost/rules_no_restricted_syntax.go +190 -26
  117. package/linthost/rules_no_useless_constructor.go +6 -36
  118. package/linthost/rules_problems.go +154 -311
  119. package/linthost/rules_promise.go +2578 -109
  120. package/linthost/rules_react_extras.go +71 -45
  121. package/linthost/rules_react_hooks.go +18 -2
  122. package/linthost/rules_react_perf.go +1 -0
  123. package/linthost/rules_react_refresh.go +1 -1
  124. package/linthost/rules_regexp.go +230 -14
  125. package/linthost/rules_security.go +45 -19
  126. package/linthost/rules_self.go +21 -1
  127. package/linthost/rules_solid.go +13 -7
  128. package/linthost/rules_storybook.go +1 -1
  129. package/linthost/rules_suggestions.go +490 -84
  130. package/linthost/rules_testing_library.go +12 -1
  131. package/linthost/rules_ts.go +227 -54
  132. package/linthost/rules_ts_async.go +0 -131
  133. package/linthost/rules_ts_no_base_to_string.go +3 -4
  134. package/linthost/rules_ts_no_misused_promises.go +817 -0
  135. package/linthost/rules_ts_no_restricted_types.go +320 -34
  136. package/linthost/rules_ts_no_unnecessary_qualifier.go +132 -55
  137. package/linthost/rules_ts_no_unsafe_assignment.go +608 -60
  138. package/linthost/rules_ts_require_array_sort_compare.go +5 -5
  139. package/linthost/rules_ts_switch_exhaustiveness_check.go +556 -86
  140. package/linthost/rules_unicorn_better_regex.go +224 -16
  141. package/linthost/rules_unicorn_consistent_destructuring.go +1002 -7
  142. package/linthost/rules_unicorn_consistent_existence_index_check.go +208 -29
  143. package/linthost/rules_unicorn_consistent_function_scoping.go +1041 -8
  144. package/linthost/rules_unicorn_consistent_template_literal_escape.go +178 -7
  145. package/linthost/rules_unicorn_escape_case.go +30 -19
  146. package/linthost/rules_unicorn_filename_case.go +763 -16
  147. package/linthost/rules_unicorn_import_style.go +783 -17
  148. package/linthost/rules_unicorn_isolated_functions.go +934 -14
  149. package/linthost/rules_unicorn_no_hex_escape.go +26 -11
  150. package/linthost/rules_unicorn_no_typeof_undefined.go +234 -25
  151. package/linthost/rules_unicorn_no_unnecessary_polyfills.go +376 -21
  152. package/linthost/rules_unicorn_no_unused_properties.go +756 -19
  153. package/linthost/rules_unicorn_number_literal_case.go +58 -39
  154. package/linthost/rules_unicorn_prefer_at.go +7 -3
  155. package/linthost/rules_unicorn_prefer_number_properties.go +381 -48
  156. package/linthost/rules_unicorn_prefer_optional_catch_binding.go +24 -24
  157. package/linthost/rules_unicorn_prefer_simple_condition_first.go +597 -19
  158. package/linthost/rules_unicorn_prefer_string_raw.go +147 -16
  159. package/linthost/rules_unicorn_prevent_abbreviations.go +1963 -95
  160. package/linthost/rules_unicorn_string_content.go +611 -15
  161. package/linthost/rules_unicorn_switch_case_break_position.go +172 -15
  162. package/linthost/rules_unicorn_template_indent.go +923 -18
  163. package/linthost/rules_unicorn_text_encoding_identifier_case.go +202 -42
  164. package/linthost/rules_unicorn_throw_new_error.go +218 -26
  165. package/linthost/rules_var.go +829 -142
  166. package/linthost/string_length.go +222 -0
  167. package/package.json +4 -3
  168. package/rule/project.go +145 -0
  169. package/rule/rule.go +58 -1
  170. package/src/index.ts +58 -17
  171. package/src/structures/ITtscLintConfig.ts +3 -0
  172. package/src/structures/TtscLintRuleSetting.ts +3 -2
  173. package/src/structures/format/ITtscLintFormat.ts +3 -2
  174. package/src/structures/format/ITtscLintFormatSortImports.ts +21 -4
  175. package/src/structures/rules/ITtscLintBoundariesRuleOptions.ts +122 -8
  176. package/src/structures/rules/ITtscLintBoundariesRules.ts +6 -8
  177. package/src/structures/rules/ITtscLintContributorRules.ts +18 -2
  178. package/src/structures/rules/ITtscLintCoreRuleOptions.ts +465 -0
  179. package/src/structures/rules/ITtscLintCoreRules.ts +122 -67
  180. package/src/structures/rules/ITtscLintRegexpRules.ts +7 -2
  181. package/src/structures/rules/ITtscLintRuleOptionsMap.ts +88 -7
  182. package/src/structures/rules/ITtscLintRules.ts +7 -2
  183. package/src/structures/rules/ITtscLintSolidRules.ts +0 -9
  184. package/src/structures/rules/ITtscLintTypeScriptRuleOptions.ts +248 -0
  185. package/src/structures/rules/ITtscLintTypeScriptRules.ts +64 -42
  186. package/src/structures/rules/ITtscLintUnicornRuleOptions.ts +350 -0
  187. package/src/structures/rules/ITtscLintUnicornRules.ts +60 -36
  188. package/src/structures/rules/index.ts +3 -0
@@ -1,29 +1,186 @@
1
- // unicorn/switch-case-break-position: the upstream rule rejects a
2
- // `break` / `return` / `throw` that is followed by further statements
3
- // inside the same `case` / `default` clause, because the trailing
4
- // statements are dead code.
1
+ // unicorn/switch-case-break-position: a case body that consists of one
2
+ // non-empty block followed by a terminating statement leaves that terminator
3
+ // visually outside the block even though both statements belong to the same
4
+ // clause. The upstream rule reports the direct `break`, `continue`, `return`,
5
+ // or `throw` and moves only break/continue statements, whose binding semantics
6
+ // cannot change when they cross the block boundary.
5
7
  //
6
- // In a well-formed TypeScript program the TypeScript-Go checker already
7
- // emits an `unreachable code` diagnostic for statements following a
8
- // terminator, so this AST-only port would either duplicate that
9
- // diagnostic (when reused as an MVP) or need scope/CFG analysis to
10
- // reproduce the exact upstream surface. The rule is registered as a
11
- // no-op until a follow-up exposes the unreachable-statement metadata
12
- // the checker computes for switch clauses.
8
+ // The fixer preserves the complete terminating statement (including labels),
9
+ // comments inside the block, the block body's indentation, and the source EOL.
10
+ // It declines edits when comments separate the block from the terminator, when
11
+ // a trailing comment belongs to the terminator, or when the block is single
12
+ // line. Return and throw remain diagnostic-only because moving them can change
13
+ // which block-scoped binding their expression resolves.
13
14
  //
14
15
  // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/switch-case-break-position.md
15
16
  package linthost
16
17
 
17
- import shimast "github.com/microsoft/typescript-go/shim/ast"
18
+ import (
19
+ "strings"
20
+
21
+ shimast "github.com/microsoft/typescript-go/shim/ast"
22
+ )
18
23
 
19
24
  type unicornSwitchCaseBreakPosition struct{}
20
25
 
21
26
  func (unicornSwitchCaseBreakPosition) Name() string {
22
27
  return "unicorn/switch-case-break-position"
23
28
  }
24
- func (unicornSwitchCaseBreakPosition) Visits() []shimast.Kind { return nil }
25
- func (unicornSwitchCaseBreakPosition) Check(*Context, *shimast.Node) {
26
- // Intentionally empty; see file-level comment.
29
+
30
+ func (unicornSwitchCaseBreakPosition) Visits() []shimast.Kind {
31
+ return []shimast.Kind{shimast.KindCaseClause, shimast.KindDefaultClause}
32
+ }
33
+
34
+ func (unicornSwitchCaseBreakPosition) Check(ctx *Context, node *shimast.Node) {
35
+ if ctx == nil || ctx.File == nil || node == nil {
36
+ return
37
+ }
38
+ clause := node.AsCaseOrDefaultClause()
39
+ if clause == nil || clause.Statements == nil {
40
+ return
41
+ }
42
+ statements := clause.Statements.Nodes
43
+ if len(statements) != 2 || statements[0] == nil || statements[1] == nil ||
44
+ statements[0].Kind != shimast.KindBlock {
45
+ return
46
+ }
47
+ blockNode, terminator := statements[0], statements[1]
48
+ block := blockNode.AsBlock()
49
+ if block == nil || block.Statements == nil || len(block.Statements.Nodes) == 0 {
50
+ return
51
+ }
52
+ keyword, fixable := switchCaseBreakPositionTerminator(terminator)
53
+ if keyword == "" {
54
+ return
55
+ }
56
+ message := "Move `" + keyword + "` inside the block statement."
57
+ if fixable {
58
+ if edits, ok := switchCaseBreakPositionFix(ctx.File, blockNode, terminator); ok {
59
+ ctx.ReportFix(terminator, message, edits...)
60
+ return
61
+ }
62
+ }
63
+ ctx.Report(terminator, message)
64
+ }
65
+
66
+ // switchCaseBreakPositionTerminator returns the statement keyword and whether
67
+ // upstream permits an automatic move. Return and throw expressions may resolve
68
+ // a different block-scoped binding after the move, so they are report-only.
69
+ func switchCaseBreakPositionTerminator(node *shimast.Node) (keyword string, fixable bool) {
70
+ if node == nil {
71
+ return "", false
72
+ }
73
+ switch node.Kind {
74
+ case shimast.KindBreakStatement:
75
+ return "break", true
76
+ case shimast.KindContinueStatement:
77
+ return "continue", true
78
+ case shimast.KindReturnStatement:
79
+ return "return", false
80
+ case shimast.KindThrowStatement:
81
+ return "throw", false
82
+ default:
83
+ return "", false
84
+ }
85
+ }
86
+
87
+ func switchCaseBreakPositionFix(
88
+ file *shimast.SourceFile,
89
+ blockNode *shimast.Node,
90
+ terminator *shimast.Node,
91
+ ) ([]TextEdit, bool) {
92
+ if file == nil || blockNode == nil || terminator == nil {
93
+ return nil, false
94
+ }
95
+ block := blockNode.AsBlock()
96
+ if block == nil || block.Statements == nil || len(block.Statements.Nodes) == 0 {
97
+ return nil, false
98
+ }
99
+ source := file.Text()
100
+ blockStart, blockEnd := tokenRange(file, blockNode)
101
+ terminatorStart, terminatorEnd := tokenRange(file, terminator)
102
+ if blockStart < 0 || blockEnd <= blockStart || blockEnd > len(source) ||
103
+ terminatorStart < blockEnd || terminatorEnd < terminatorStart || terminatorEnd > len(source) ||
104
+ source[blockEnd-1] != '}' {
105
+ return nil, false
106
+ }
107
+
108
+ // Moving out of a one-line block would produce a malformed or misleading
109
+ // layout. This is the same source-location gate used by upstream.
110
+ blockSource := source[blockStart:blockEnd]
111
+ if !strings.ContainsAny(blockSource, "\r\n") {
112
+ return nil, false
113
+ }
114
+
115
+ gap := source[blockEnd:terminatorStart]
116
+ if strings.TrimSpace(gap) != "" || hasCommentBetween(source, blockEnd, terminatorStart) {
117
+ return nil, false
118
+ }
119
+ if switchCaseBreakPositionHasTrailingSameLineComment(source, terminatorEnd) {
120
+ return nil, false
121
+ }
122
+
123
+ body := block.Statements.Nodes
124
+ lastStatement := body[len(body)-1]
125
+ lastStart, _ := tokenRange(file, lastStatement)
126
+ if lastStatement == nil || lastStart < blockStart || lastStatement.End() > blockEnd-1 {
127
+ return nil, false
128
+ }
129
+ insertPos := lastStatement.End()
130
+ if _, commentEnd, ok := lastCommentInTrivia(source, insertPos, blockEnd-1); ok {
131
+ insertPos = commentEnd
132
+ }
133
+ if insertPos < lastStatement.End() || insertPos > blockEnd-1 {
134
+ return nil, false
135
+ }
136
+
137
+ indent := switchCaseBreakPositionIndent(source, lastStart)
138
+ newline := switchCaseBreakPositionNewline(blockSource)
139
+ statementText := source[terminatorStart:terminatorEnd]
140
+ return []TextEdit{
141
+ {Pos: insertPos, End: insertPos, Text: newline + indent + statementText},
142
+ {Pos: blockEnd, End: terminatorEnd, Text: ""},
143
+ }, true
144
+ }
145
+
146
+ // switchCaseBreakPositionIndent mirrors upstream getIndentString: use only the
147
+ // trailing horizontal whitespace before the last body statement, not arbitrary
148
+ // tokens that may precede it on the same physical line.
149
+ func switchCaseBreakPositionIndent(source string, pos int) string {
150
+ if pos < 0 || pos > len(source) {
151
+ return ""
152
+ }
153
+ lineStart := strings.LastIndex(source[:pos], "\n") + 1
154
+ indentStart := pos
155
+ for indentStart > lineStart &&
156
+ (source[indentStart-1] == ' ' || source[indentStart-1] == '\t') {
157
+ indentStart--
158
+ }
159
+ return source[indentStart:pos]
160
+ }
161
+
162
+ func switchCaseBreakPositionNewline(blockSource string) string {
163
+ if index := strings.IndexByte(blockSource, '\n'); index >= 0 {
164
+ if index > 0 && blockSource[index-1] == '\r' {
165
+ return "\r\n"
166
+ }
167
+ return "\n"
168
+ }
169
+ if strings.ContainsRune(blockSource, '\r') {
170
+ return "\r"
171
+ }
172
+ return "\n"
173
+ }
174
+
175
+ func switchCaseBreakPositionHasTrailingSameLineComment(source string, end int) bool {
176
+ if end < 0 || end > len(source) {
177
+ return true
178
+ }
179
+ lineEnd := len(source)
180
+ if offset := strings.IndexAny(source[end:], "\r\n"); offset >= 0 {
181
+ lineEnd = end + offset
182
+ }
183
+ return hasCommentBetween(source, end, lineEnd)
27
184
  }
28
185
 
29
186
  func init() {