@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,17 +1,51 @@
1
- // unicorn/prefer-string-raw: a string literal whose source contains
2
- // `\\` (an escaped backslash) is using the escape syntax to represent a
3
- // literal backslash. The same value, written through `String.raw` as
4
- // a template literal, drops every backslash escape and reads as the
5
- // literal text the author meant — particularly noticeable for Windows
6
- // paths, regex source strings, and TeX-shaped snippets.
1
+ // unicorn/prefer-string-raw: a string literal whose source spells a
2
+ // backslash as the escape `\\` is using escape syntax to represent a
3
+ // literal backslash. The same value, written through `String.raw` as a
4
+ // template literal, drops every backslash escape and reads as the literal
5
+ // text the author meant — particularly noticeable for Windows paths,
6
+ // regex source strings, and TeX-shaped snippets.
7
7
  //
8
8
  // AST-only: visit `KindStringLiteral` and
9
- // `KindNoSubstitutionTemplateLiteral`. The match keys on the raw source
10
- // bytes of the literal node `nodeText` returns the as-written source
11
- // and fires when those bytes contain the two-character sequence `\\`,
12
- // i.e. an escaped backslash that `String.raw` would render literally.
13
- // Untagged template literals with substitutions are out of scope; this
14
- // rule only addresses the "single literal of fixed text" case.
9
+ // `KindNoSubstitutionTemplateLiteral`. `\\` is invisible in a literal's
10
+ // cooked value, so both branches re-read the raw source bytes of the node
11
+ // and report only when a `String.raw` template would reproduce the value
12
+ // exactly. Upstream's autofix is not ported; the rule is report-only.
13
+ //
14
+ // String literals mirror upstream's `Literal` handler, which returns
15
+ // before reporting when
16
+ //
17
+ // - the raw payload's last character is a backslash: a template cannot
18
+ // end in one, it would escape the closing backtick;
19
+ // - the raw payload holds no `\\` at all: no escape to drop;
20
+ // - the raw payload holds a backtick or `${`: the template would
21
+ // terminate early or interpolate;
22
+ // - the literal spans more than one line;
23
+ // - unescaping only `\\` and `\<quote>` out of the raw payload does not
24
+ // reproduce the cooked value: some OTHER escape (`\t`, `\n`, a
25
+ // unicode escape, an escaped non-delimiter quote, …) is present, and
26
+ // `String.raw` would emit its source spelling verbatim instead of the
27
+ // character it stands for, silently changing the value.
28
+ //
29
+ // No-substitution templates mirror upstream's `TemplateLiteral` handler:
30
+ // the quasi of a tagged template is skipped (the tag already observes the
31
+ // raw text), a raw payload equal to its cooked value has no escape to
32
+ // drop, a cooked value ending in a backslash cannot be respelled raw, and
33
+ // the raw payload must unescape — `\\` only, a template has no delimiter
34
+ // quote to escape — back to the cooked value. Multi-line templates stay
35
+ // reportable, unlike multi-line string literals: a template already
36
+ // carries its newlines literally. As in ESLint, the raw payload is read
37
+ // with CR / CRLF collapsed to LF, the same normalization the TypeScript
38
+ // scanner applies when it cooks a template token.
39
+ //
40
+ // Not ported: upstream also suppresses the report by POSITION
41
+ // (`isStringRawRestricted` — directive prologues, property keys, module
42
+ // specifiers, TypeScript literal types and enum members, …) and inside
43
+ // Jest inline snapshots. Of that list only JSX attribute values are
44
+ // covered here, and by value rather than by position: a JSX attribute
45
+ // string has no escape sequences, so its cooked text keeps the doubled
46
+ // backslash that the unescape above drops. Untagged template literals
47
+ // WITH substitutions are out of scope too; this rule only addresses the
48
+ // "single literal of fixed text" case.
15
49
  // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-string-raw.md
16
50
  package linthost
17
51
 
@@ -19,8 +53,11 @@ import (
19
53
  "strings"
20
54
 
21
55
  shimast "github.com/microsoft/typescript-go/shim/ast"
56
+ shimscanner "github.com/microsoft/typescript-go/shim/scanner"
22
57
  )
23
58
 
59
+ const unicornPreferStringRawMessage = "Prefer `String.raw` for strings with backslash escapes."
60
+
24
61
  type unicornPreferStringRaw struct{}
25
62
 
26
63
  func (unicornPreferStringRaw) Name() string { return "unicorn/prefer-string-raw" }
@@ -28,14 +65,108 @@ func (unicornPreferStringRaw) Visits() []shimast.Kind {
28
65
  return []shimast.Kind{shimast.KindStringLiteral, shimast.KindNoSubstitutionTemplateLiteral}
29
66
  }
30
67
  func (unicornPreferStringRaw) Check(ctx *Context, node *shimast.Node) {
31
- raw := nodeText(ctx.File, node)
32
- if raw == "" {
68
+ if ctx == nil || ctx.File == nil || node == nil {
69
+ return
70
+ }
71
+ switch node.Kind {
72
+ case shimast.KindStringLiteral:
73
+ unicornPreferStringRawCheckString(ctx, node)
74
+ case shimast.KindNoSubstitutionTemplateLiteral:
75
+ unicornPreferStringRawCheckTemplate(ctx, node)
76
+ }
77
+ }
78
+
79
+ // unicornPreferStringRawCheckString reports a single-quoted or
80
+ // double-quoted literal whose `\\` escapes — and nothing else — separate
81
+ // its raw source from its value.
82
+ //
83
+ // A literal without a matching closing quote is an unterminated token the
84
+ // parser recovered from; there is no payload to respell, so it is left
85
+ // alone rather than sliced blindly.
86
+ func unicornPreferStringRawCheckString(ctx *Context, node *shimast.Node) {
87
+ pos, end := tokenRange(ctx.File, node)
88
+ if pos < 0 || end-pos < 2 {
33
89
  return
34
90
  }
35
- if !strings.Contains(raw, `\\`) {
91
+ source := ctx.File.Text()
92
+ quote := source[pos]
93
+ if (quote != '\'' && quote != '"') || source[end-1] != quote {
36
94
  return
37
95
  }
38
- ctx.Report(node, "Prefer `String.raw` for strings with backslash escapes.")
96
+ raw := source[pos+1 : end-1]
97
+ if strings.HasSuffix(raw, `\`) ||
98
+ !strings.Contains(raw, `\\`) ||
99
+ strings.Contains(raw, "`") ||
100
+ strings.Contains(raw, "${") {
101
+ return
102
+ }
103
+ if shimscanner.GetECMALineOfPosition(ctx.File, pos) != shimscanner.GetECMALineOfPosition(ctx.File, end) {
104
+ return
105
+ }
106
+ if unicornPreferStringRawUnescapeBackslash(raw, quote) != stringLiteralText(node) {
107
+ return
108
+ }
109
+ ctx.Report(node, unicornPreferStringRawMessage)
110
+ }
111
+
112
+ // unicornPreferStringRawCheckTemplate reports an untagged
113
+ // no-substitution template whose `\\` escapes — and nothing else —
114
+ // separate its raw source from its cooked value, so prefixing it with
115
+ // `String.raw` keeps the value and drops the escapes.
116
+ func unicornPreferStringRawCheckTemplate(ctx *Context, node *shimast.Node) {
117
+ if isTaggedTemplateQuasi(node) {
118
+ return
119
+ }
120
+ pos, end := tokenRange(ctx.File, node)
121
+ if pos < 0 || end-pos < 2 {
122
+ return
123
+ }
124
+ source := ctx.File.Text()
125
+ if source[pos] != '`' || source[end-1] != '`' {
126
+ return
127
+ }
128
+ raw := normalizeTemplateRaw(source[pos+1 : end-1])
129
+ cooked := stringLiteralText(node)
130
+ if raw == cooked || strings.HasSuffix(cooked, `\`) {
131
+ return
132
+ }
133
+ if unicornPreferStringRawUnescapeBackslash(raw, 0) != cooked {
134
+ return
135
+ }
136
+ ctx.Report(node, unicornPreferStringRawMessage)
137
+ }
138
+
139
+ // unicornPreferStringRawUnescapeBackslash is upstream's
140
+ // `unescapeBackslash(text, quote)`:
141
+ //
142
+ // text.replaceAll(new RegExp(String.raw`\\(?<escapedCharacter>[\\${quote}])`, "g"), "$<escapedCharacter>")
143
+ //
144
+ // It drops the backslash from `\\` and from an escaped delimiter quote,
145
+ // and leaves every other escape sequence spelled out exactly as written.
146
+ // The result therefore equals the literal's cooked value only when those
147
+ // two are the only escapes present — which is precisely when `String.raw`
148
+ // can respell the literal without changing it.
149
+ //
150
+ // `quote` is the delimiter byte (`'` or `"`), or 0 for a template, whose
151
+ // only escapable delimiter is the backslash itself. Scanning bytes is
152
+ // UTF-8 safe: `\` is ASCII and never appears inside a multi-byte
153
+ // sequence, so multi-byte and astral runes are copied through untouched.
154
+ // Matches are consumed left to right and never overlap, so a run of
155
+ // backslashes halves exactly as the global regular expression does.
156
+ func unicornPreferStringRawUnescapeBackslash(text string, quote byte) string {
157
+ var unescaped strings.Builder
158
+ for index := 0; index < len(text); index++ {
159
+ character := text[index]
160
+ if character == '\\' && index+1 < len(text) {
161
+ if next := text[index+1]; next == '\\' || (quote != 0 && next == quote) {
162
+ unescaped.WriteByte(next)
163
+ index++
164
+ continue
165
+ }
166
+ }
167
+ unescaped.WriteByte(character)
168
+ }
169
+ return unescaped.String()
39
170
  }
40
171
 
41
172
  func init() {