@ttsc/lint 0.18.4 → 0.19.1
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 +125 -43
- package/go.mod +5 -4
- package/internal/rulecode/rulecode.go +88 -0
- package/lib/index.d.ts +10 -1
- package/lib/index.js +45 -17
- package/lib/index.js.map +1 -1
- package/lib/structures/ITtscLintConfig.d.ts +3 -0
- package/lib/structures/TtscLintRuleSetting.d.ts +3 -2
- package/lib/structures/format/ITtscLintFormat.d.ts +3 -2
- package/lib/structures/format/ITtscLintFormatSortImports.d.ts +20 -4
- package/lib/structures/rules/ITtscLintBoundariesRuleOptions.d.ts +80 -8
- package/lib/structures/rules/ITtscLintBoundariesRules.d.ts +6 -8
- package/lib/structures/rules/ITtscLintContributorRules.d.ts +18 -2
- package/lib/structures/rules/ITtscLintCoreRuleOptions.d.ts +347 -0
- package/lib/structures/rules/ITtscLintCoreRuleOptions.js +3 -0
- package/lib/structures/rules/ITtscLintCoreRuleOptions.js.map +1 -0
- package/lib/structures/rules/ITtscLintCoreRules.d.ts +101 -67
- package/lib/structures/rules/ITtscLintRegexpRules.d.ts +7 -2
- package/lib/structures/rules/ITtscLintRuleOptionsMap.d.ts +53 -7
- package/lib/structures/rules/ITtscLintRules.d.ts +6 -2
- package/lib/structures/rules/ITtscLintSolidRules.d.ts +0 -8
- package/lib/structures/rules/ITtscLintTypeScriptRuleOptions.d.ts +206 -0
- package/lib/structures/rules/ITtscLintTypeScriptRuleOptions.js +8 -0
- package/lib/structures/rules/ITtscLintTypeScriptRuleOptions.js.map +1 -0
- package/lib/structures/rules/ITtscLintTypeScriptRules.d.ts +55 -42
- package/lib/structures/rules/ITtscLintUnicornRuleOptions.d.ts +276 -0
- package/lib/structures/rules/ITtscLintUnicornRuleOptions.js +3 -0
- package/lib/structures/rules/ITtscLintUnicornRuleOptions.js.map +1 -0
- package/lib/structures/rules/ITtscLintUnicornRules.d.ts +44 -36
- package/lib/structures/rules/index.d.ts +3 -0
- package/lib/structures/rules/index.js +3 -0
- package/lib/structures/rules/index.js.map +1 -1
- package/linthost/ast_helpers.go +521 -23
- package/linthost/ast_selector_matcher.go +1628 -0
- package/linthost/ast_selector_parser.go +628 -0
- package/linthost/comment_scan.go +154 -0
- package/linthost/compile.go +129 -79
- package/linthost/config.go +352 -88
- package/linthost/config_format.go +15 -1
- package/linthost/contrib_adapter.go +47 -8
- package/linthost/declaration_rules.go +12 -11
- package/linthost/directives.go +9 -67
- package/linthost/dispatch.go +37 -3
- package/linthost/engine.go +368 -53
- package/linthost/escape_string.go +77 -0
- package/linthost/fix.go +133 -23
- package/linthost/flags_gen.go +18 -17
- package/linthost/format.go +73 -167
- package/linthost/format_editor_settings.go +134 -26
- package/linthost/grapheme_tables_gen.go +1920 -0
- package/linthost/host.go +159 -61
- package/linthost/literal_escape_scan.go +117 -0
- package/linthost/lsp.go +545 -98
- package/linthost/numeric_literal_precision.go +228 -0
- package/linthost/polyfill_browserslist.go +1439 -0
- package/linthost/polyfill_browserslist_config.go +603 -0
- package/linthost/polyfill_corejs.go +750 -0
- package/linthost/polyfill_data.go +113 -0
- package/linthost/polyfill_data_gen.json +39868 -0
- package/linthost/print_nodes_array.go +7 -1
- package/linthost/print_nodes_object.go +7 -1
- package/linthost/project_engine.go +231 -0
- package/linthost/project_rules.go +78 -0
- package/linthost/regex_clean.go +191 -0
- package/linthost/regex_tree.go +1544 -0
- package/linthost/regex_tree_optimizer.go +1685 -0
- package/linthost/regexp_cache.go +44 -0
- package/linthost/rule_codes.go +105 -0
- package/linthost/rule_codes.json +745 -0
- package/linthost/rules_ban_ts_comment.go +312 -0
- package/linthost/rules_boundaries.go +128 -43
- package/linthost/rules_boundaries_dependencies.go +1013 -0
- package/linthost/rules_core_extra.go +62 -92
- package/linthost/rules_cypress.go +1 -1
- package/linthost/rules_default_case.go +87 -11
- package/linthost/rules_dupes.go +38 -13
- package/linthost/rules_empty.go +188 -20
- package/linthost/rules_escape.go +62 -48
- package/linthost/rules_format_arrow_parens.go +19 -5
- package/linthost/rules_format_bracket_spacing.go +1 -1
- package/linthost/rules_format_clause_join.go +1 -1
- package/linthost/rules_format_declaration_header.go +31 -19
- package/linthost/rules_format_indent.go +1 -1
- package/linthost/rules_format_jsdoc.go +1 -1
- package/linthost/rules_format_orphan_semi.go +1 -1
- package/linthost/rules_format_parameter_properties.go +17 -7
- package/linthost/rules_format_print_width.go +1 -1
- package/linthost/rules_format_quote_props.go +1 -1
- package/linthost/rules_format_quotes.go +1 -1
- package/linthost/rules_format_semi.go +106 -79
- package/linthost/rules_format_sort_imports.go +79 -45
- package/linthost/rules_format_statement_split.go +1 -1
- package/linthost/rules_format_ternary_nullish_parens.go +1 -1
- package/linthost/rules_format_trailing_comma.go +64 -1
- package/linthost/rules_format_whitespace.go +1 -1
- package/linthost/rules_functional.go +21 -22
- package/linthost/rules_gap.go +80 -3
- package/linthost/rules_grouped_accessor_pairs.go +84 -25
- package/linthost/rules_guard_for_in.go +64 -147
- package/linthost/rules_jsx_a11y.go +232 -22
- package/linthost/rules_logic.go +84 -38
- package/linthost/rules_nextjs.go +105 -16
- package/linthost/rules_no_class_assign.go +70 -0
- package/linthost/rules_no_duplicate_imports.go +266 -0
- package/linthost/rules_no_else_return.go +156 -38
- package/linthost/rules_no_extend_native.go +113 -17
- package/linthost/rules_no_fallthrough.go +1013 -0
- package/linthost/rules_no_func_assign.go +70 -0
- package/linthost/rules_no_import_assign.go +278 -86
- package/linthost/rules_no_inner_declarations.go +186 -0
- package/linthost/rules_no_loop_func.go +438 -53
- package/linthost/rules_no_mixed_operators.go +208 -52
- package/linthost/rules_no_param_reassign.go +376 -61
- package/linthost/rules_no_promise_executor_return.go +156 -0
- package/linthost/rules_no_restricted_imports.go +1013 -57
- package/linthost/rules_no_restricted_syntax.go +190 -26
- package/linthost/rules_no_useless_constructor.go +6 -36
- package/linthost/rules_problems.go +154 -311
- package/linthost/rules_promise.go +2578 -109
- package/linthost/rules_react_extras.go +71 -45
- package/linthost/rules_react_hooks.go +18 -2
- package/linthost/rules_react_perf.go +1 -0
- package/linthost/rules_react_refresh.go +1 -1
- package/linthost/rules_regexp.go +230 -14
- package/linthost/rules_security.go +45 -19
- package/linthost/rules_self.go +21 -1
- package/linthost/rules_solid.go +13 -7
- package/linthost/rules_storybook.go +1 -1
- package/linthost/rules_suggestions.go +490 -84
- package/linthost/rules_testing_library.go +12 -1
- package/linthost/rules_ts.go +227 -54
- package/linthost/rules_ts_async.go +0 -131
- package/linthost/rules_ts_no_base_to_string.go +3 -4
- package/linthost/rules_ts_no_misused_promises.go +817 -0
- package/linthost/rules_ts_no_restricted_types.go +320 -34
- package/linthost/rules_ts_no_unnecessary_qualifier.go +132 -55
- package/linthost/rules_ts_no_unsafe_assignment.go +608 -60
- package/linthost/rules_ts_require_array_sort_compare.go +5 -5
- package/linthost/rules_ts_switch_exhaustiveness_check.go +556 -86
- package/linthost/rules_unicorn_better_regex.go +224 -16
- package/linthost/rules_unicorn_consistent_destructuring.go +1002 -7
- package/linthost/rules_unicorn_consistent_existence_index_check.go +208 -29
- package/linthost/rules_unicorn_consistent_function_scoping.go +1041 -8
- package/linthost/rules_unicorn_consistent_template_literal_escape.go +178 -7
- package/linthost/rules_unicorn_escape_case.go +30 -19
- package/linthost/rules_unicorn_filename_case.go +763 -16
- package/linthost/rules_unicorn_import_style.go +783 -17
- package/linthost/rules_unicorn_isolated_functions.go +934 -14
- package/linthost/rules_unicorn_no_hex_escape.go +26 -11
- package/linthost/rules_unicorn_no_typeof_undefined.go +234 -25
- package/linthost/rules_unicorn_no_unnecessary_polyfills.go +376 -21
- package/linthost/rules_unicorn_no_unused_properties.go +756 -19
- package/linthost/rules_unicorn_number_literal_case.go +58 -39
- package/linthost/rules_unicorn_prefer_at.go +7 -3
- package/linthost/rules_unicorn_prefer_number_properties.go +381 -48
- package/linthost/rules_unicorn_prefer_optional_catch_binding.go +24 -24
- package/linthost/rules_unicorn_prefer_simple_condition_first.go +597 -19
- package/linthost/rules_unicorn_prefer_string_raw.go +147 -16
- package/linthost/rules_unicorn_prevent_abbreviations.go +1963 -95
- package/linthost/rules_unicorn_string_content.go +611 -15
- package/linthost/rules_unicorn_switch_case_break_position.go +172 -15
- package/linthost/rules_unicorn_template_indent.go +923 -18
- package/linthost/rules_unicorn_text_encoding_identifier_case.go +202 -42
- package/linthost/rules_unicorn_throw_new_error.go +218 -26
- package/linthost/rules_var.go +829 -142
- package/linthost/string_length.go +222 -0
- package/package.json +4 -3
- package/rule/project.go +206 -0
- package/rule/rule.go +58 -1
- package/src/index.ts +58 -17
- package/src/structures/ITtscLintConfig.ts +3 -0
- package/src/structures/TtscLintRuleSetting.ts +3 -2
- package/src/structures/format/ITtscLintFormat.ts +3 -2
- package/src/structures/format/ITtscLintFormatSortImports.ts +21 -4
- package/src/structures/rules/ITtscLintBoundariesRuleOptions.ts +122 -8
- package/src/structures/rules/ITtscLintBoundariesRules.ts +6 -8
- package/src/structures/rules/ITtscLintContributorRules.ts +18 -2
- package/src/structures/rules/ITtscLintCoreRuleOptions.ts +465 -0
- package/src/structures/rules/ITtscLintCoreRules.ts +122 -67
- package/src/structures/rules/ITtscLintRegexpRules.ts +7 -2
- package/src/structures/rules/ITtscLintRuleOptionsMap.ts +88 -7
- package/src/structures/rules/ITtscLintRules.ts +7 -2
- package/src/structures/rules/ITtscLintSolidRules.ts +0 -9
- package/src/structures/rules/ITtscLintTypeScriptRuleOptions.ts +248 -0
- package/src/structures/rules/ITtscLintTypeScriptRules.ts +64 -42
- package/src/structures/rules/ITtscLintUnicornRuleOptions.ts +350 -0
- package/src/structures/rules/ITtscLintUnicornRules.ts +60 -36
- package/src/structures/rules/index.ts +3 -0
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
package linthost
|
|
2
2
|
|
|
3
3
|
import (
|
|
4
|
+
"bytes"
|
|
4
5
|
"encoding/json"
|
|
5
6
|
"errors"
|
|
7
|
+
"io"
|
|
6
8
|
"os"
|
|
7
9
|
"path/filepath"
|
|
8
10
|
"strings"
|
|
@@ -38,10 +40,10 @@ func loadFormatRules(pluginsJSON, cwd, tsconfigPath string) (RuleResolver, error
|
|
|
38
40
|
//
|
|
39
41
|
// This is consulted only when lint.config.* configures no `format` block: a
|
|
40
42
|
// configured format block always wins and never reaches this path. Within
|
|
41
|
-
// settings.json
|
|
42
|
-
//
|
|
43
|
-
//
|
|
44
|
-
//
|
|
43
|
+
// settings.json, matching combined language sections are applied in source
|
|
44
|
+
// order and an exact single-language section is applied last, mirroring VS
|
|
45
|
+
// Code's own resolution. Pass language="" to skip language sections (e.g. the
|
|
46
|
+
// project-wide `ttsc format` CLI path).
|
|
45
47
|
//
|
|
46
48
|
// Mapping (values use JSON types so they parse identically to a real `format`
|
|
47
49
|
// block, where numbers decode as float64):
|
|
@@ -63,17 +65,22 @@ func editorFormatOverrides(startDir string, language string) map[string]any {
|
|
|
63
65
|
if !ok {
|
|
64
66
|
return out
|
|
65
67
|
}
|
|
66
|
-
// Top-level keys first, then language
|
|
67
|
-
|
|
68
|
+
// Top-level keys first, then matching combined language sections in source
|
|
69
|
+
// order. VS Code holds an exact single-language section aside and applies it
|
|
70
|
+
// last, regardless of where its full selector appears in settings.json.
|
|
71
|
+
applyEditorSettings(out, settings.values)
|
|
68
72
|
if language != "" {
|
|
69
|
-
|
|
70
|
-
|
|
73
|
+
var exact map[string]any
|
|
74
|
+
for _, section := range settings.languageSections {
|
|
75
|
+
if len(section.identifiers) == 1 && section.identifiers[0] == language {
|
|
76
|
+
exact = section.values
|
|
71
77
|
continue
|
|
72
78
|
}
|
|
73
|
-
if section,
|
|
74
|
-
applyEditorSettings(out, section)
|
|
79
|
+
if languageSectionContains(section.identifiers, language) {
|
|
80
|
+
applyEditorSettings(out, section.values)
|
|
75
81
|
}
|
|
76
82
|
}
|
|
83
|
+
applyEditorSettings(out, exact)
|
|
77
84
|
}
|
|
78
85
|
return out
|
|
79
86
|
}
|
|
@@ -105,20 +112,41 @@ func applyEditorSettings(out map[string]any, settings map[string]any) {
|
|
|
105
112
|
}
|
|
106
113
|
}
|
|
107
114
|
|
|
108
|
-
//
|
|
109
|
-
//
|
|
110
|
-
//
|
|
111
|
-
// language
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
+
// languageSectionIdentifiers parses a complete VS Code language selector such
|
|
116
|
+
// as "[typescript]" or "[javascript][typescript][json]". Each full selector is
|
|
117
|
+
// one override scope; its identifiers are used only to determine whether that
|
|
118
|
+
// scope applies to the requested language. Identifiers are trimmed and
|
|
119
|
+
// deduplicated, and empty normalized identifiers are discarded, before
|
|
120
|
+
// exact-versus-combined precedence is decided.
|
|
121
|
+
func languageSectionIdentifiers(key string) ([]string, bool) {
|
|
122
|
+
identifiers := []string{}
|
|
123
|
+
for len(key) != 0 {
|
|
124
|
+
if key[0] != '[' {
|
|
125
|
+
return nil, false
|
|
126
|
+
}
|
|
127
|
+
close := strings.IndexByte(key, ']')
|
|
128
|
+
if close <= 1 {
|
|
129
|
+
return nil, false
|
|
130
|
+
}
|
|
131
|
+
identifier := strings.TrimSpace(key[1:close])
|
|
132
|
+
if identifier == "" {
|
|
133
|
+
key = key[close+1:]
|
|
134
|
+
continue
|
|
135
|
+
}
|
|
136
|
+
if !languageSectionContains(identifiers, identifier) {
|
|
137
|
+
identifiers = append(identifiers, identifier)
|
|
138
|
+
}
|
|
139
|
+
key = key[close+1:]
|
|
115
140
|
}
|
|
116
|
-
|
|
141
|
+
return identifiers, len(identifiers) != 0
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
func languageSectionContains(identifiers []string, language string) bool {
|
|
145
|
+
if language == "" {
|
|
117
146
|
return false
|
|
118
147
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
if lang == language {
|
|
148
|
+
for _, identifier := range identifiers {
|
|
149
|
+
if identifier == language {
|
|
122
150
|
return true
|
|
123
151
|
}
|
|
124
152
|
}
|
|
@@ -143,30 +171,110 @@ func vscodeLanguageID(filePath string) string {
|
|
|
143
171
|
}
|
|
144
172
|
}
|
|
145
173
|
|
|
174
|
+
type vscodeSettings struct {
|
|
175
|
+
values map[string]any
|
|
176
|
+
languageSections []vscodeLanguageSection
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
type vscodeLanguageSection struct {
|
|
180
|
+
identifiers []string
|
|
181
|
+
values map[string]any
|
|
182
|
+
}
|
|
183
|
+
|
|
146
184
|
// loadNearestVSCodeSettings walks up from startDir looking for a
|
|
147
185
|
// `.vscode/settings.json`, returning the first one found decoded as a JSONC
|
|
148
186
|
// document. It returns ok=false when none exists or the file cannot be parsed,
|
|
149
187
|
// so a broken settings file degrades to the format defaults instead of breaking
|
|
150
188
|
// the formatter.
|
|
151
|
-
func loadNearestVSCodeSettings(startDir string) (
|
|
189
|
+
func loadNearestVSCodeSettings(startDir string) (vscodeSettings, bool) {
|
|
152
190
|
dir := startDir
|
|
153
191
|
for {
|
|
154
192
|
candidate := filepath.Join(dir, ".vscode", "settings.json")
|
|
155
193
|
if data, err := os.ReadFile(candidate); err == nil {
|
|
156
|
-
|
|
157
|
-
|
|
194
|
+
data = bytes.TrimPrefix(data, []byte{0xEF, 0xBB, 0xBF})
|
|
195
|
+
parsed, err := decodeVSCodeSettings(stripJSONC(data))
|
|
196
|
+
if err == nil {
|
|
158
197
|
return parsed, true
|
|
159
198
|
}
|
|
160
|
-
return
|
|
199
|
+
return vscodeSettings{}, false
|
|
161
200
|
}
|
|
162
201
|
parent := filepath.Dir(dir)
|
|
163
202
|
if parent == dir {
|
|
164
|
-
return
|
|
203
|
+
return vscodeSettings{}, false
|
|
165
204
|
}
|
|
166
205
|
dir = parent
|
|
167
206
|
}
|
|
168
207
|
}
|
|
169
208
|
|
|
209
|
+
// decodeVSCodeSettings decodes the top-level JSON object without discarding
|
|
210
|
+
// declaration order. encoding/json maps are intentionally unordered, while VS
|
|
211
|
+
// Code merges matching combined language sections in the order they appear in
|
|
212
|
+
// settings.json and applies the exact single-language section afterwards. A
|
|
213
|
+
// repeated property keeps its first insertion position and final value, as it
|
|
214
|
+
// does in VS Code's parsed settings object.
|
|
215
|
+
func decodeVSCodeSettings(data []byte) (vscodeSettings, error) {
|
|
216
|
+
decoder := json.NewDecoder(bytes.NewReader(data))
|
|
217
|
+
token, err := decoder.Token()
|
|
218
|
+
if err != nil {
|
|
219
|
+
return vscodeSettings{}, err
|
|
220
|
+
}
|
|
221
|
+
if token != json.Delim('{') {
|
|
222
|
+
return vscodeSettings{}, errors.New("VS Code settings must be a JSON object")
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
orderedKeys := []string{}
|
|
226
|
+
values := map[string]any{}
|
|
227
|
+
for decoder.More() {
|
|
228
|
+
token, err := decoder.Token()
|
|
229
|
+
if err != nil {
|
|
230
|
+
return vscodeSettings{}, err
|
|
231
|
+
}
|
|
232
|
+
key, ok := token.(string)
|
|
233
|
+
if !ok {
|
|
234
|
+
return vscodeSettings{}, errors.New("VS Code setting key must be a string")
|
|
235
|
+
}
|
|
236
|
+
var value any
|
|
237
|
+
if err := decoder.Decode(&value); err != nil {
|
|
238
|
+
return vscodeSettings{}, err
|
|
239
|
+
}
|
|
240
|
+
if _, exists := values[key]; !exists {
|
|
241
|
+
orderedKeys = append(orderedKeys, key)
|
|
242
|
+
}
|
|
243
|
+
values[key] = value
|
|
244
|
+
}
|
|
245
|
+
token, err = decoder.Token()
|
|
246
|
+
if err != nil {
|
|
247
|
+
return vscodeSettings{}, err
|
|
248
|
+
}
|
|
249
|
+
if token != json.Delim('}') {
|
|
250
|
+
return vscodeSettings{}, errors.New("VS Code settings object is not closed")
|
|
251
|
+
}
|
|
252
|
+
if err := decoder.Decode(&struct{}{}); !errors.Is(err, io.EOF) {
|
|
253
|
+
if err != nil {
|
|
254
|
+
return vscodeSettings{}, err
|
|
255
|
+
}
|
|
256
|
+
return vscodeSettings{}, errors.New("VS Code settings contain trailing JSON")
|
|
257
|
+
}
|
|
258
|
+
settings := vscodeSettings{values: map[string]any{}}
|
|
259
|
+
for _, key := range orderedKeys {
|
|
260
|
+
value := values[key]
|
|
261
|
+
identifiers, isLanguageSection := languageSectionIdentifiers(key)
|
|
262
|
+
if !isLanguageSection {
|
|
263
|
+
settings.values[key] = value
|
|
264
|
+
continue
|
|
265
|
+
}
|
|
266
|
+
section, ok := value.(map[string]any)
|
|
267
|
+
if !ok {
|
|
268
|
+
continue
|
|
269
|
+
}
|
|
270
|
+
settings.languageSections = append(settings.languageSections, vscodeLanguageSection{
|
|
271
|
+
identifiers: identifiers,
|
|
272
|
+
values: section,
|
|
273
|
+
})
|
|
274
|
+
}
|
|
275
|
+
return settings, nil
|
|
276
|
+
}
|
|
277
|
+
|
|
170
278
|
// stripJSONC removes `//` line comments, `/* */` block comments, and trailing
|
|
171
279
|
// commas from a JSONC byte slice so encoding/json can parse VS Code's
|
|
172
280
|
// settings.json. It is string-literal aware: comment markers and commas inside
|