@ttsc/lint 0.18.3 → 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.
- package/README.md +95 -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 +129 -25
- 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 +160 -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 +151 -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 +145 -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
|
@@ -10,21 +10,32 @@
|
|
|
10
10
|
// `package main` init functions and the relative order across files in
|
|
11
11
|
// the same package is alphabetical — so we cannot blindly run the
|
|
12
12
|
// contributor wiring from a file-level `init()` and expect built-in
|
|
13
|
-
// registration to have already completed. Instead, `
|
|
14
|
-
// is invoked explicitly from `
|
|
15
|
-
//
|
|
13
|
+
// registration to have already completed. Instead, `registerContributorsOnce`
|
|
14
|
+
// is invoked explicitly from `run` after all built-in `init` calls have
|
|
15
|
+
// settled, which makes the collision check meaningful.
|
|
16
16
|
package linthost
|
|
17
17
|
|
|
18
18
|
import (
|
|
19
19
|
"fmt"
|
|
20
20
|
"os"
|
|
21
21
|
"sort"
|
|
22
|
+
"sync"
|
|
22
23
|
|
|
23
24
|
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
24
25
|
|
|
25
26
|
"github.com/samchon/ttsc/packages/lint/rule"
|
|
26
27
|
)
|
|
27
28
|
|
|
29
|
+
var contributorBootstrap sync.Once
|
|
30
|
+
|
|
31
|
+
// registerContributorsOnce installs the immutable init-time contributor
|
|
32
|
+
// registries exactly once. Main is a reusable library entry and may be called
|
|
33
|
+
// concurrently, so every caller must wait for the same completed bootstrap
|
|
34
|
+
// before constructing an Engine that reads the global rule maps.
|
|
35
|
+
func registerContributorsOnce() {
|
|
36
|
+
contributorBootstrap.Do(registerContributors)
|
|
37
|
+
}
|
|
38
|
+
|
|
28
39
|
// registerContributors wraps every contributor rule registered through
|
|
29
40
|
// the public `rule` package into the engine's internal `Rule` interface
|
|
30
41
|
// and pushes it onto the same dispatch table the built-in rules use.
|
|
@@ -34,12 +45,23 @@ import (
|
|
|
34
45
|
// with a stderr warning. The host prefers a deterministic, debuggable
|
|
35
46
|
// outcome over panicking inside startup.
|
|
36
47
|
func registerContributors() {
|
|
37
|
-
|
|
48
|
+
registered := rule.Registered()
|
|
49
|
+
contributors := make([]contributorMetadata, 0, len(registered))
|
|
50
|
+
for _, contributor := range registered {
|
|
51
|
+
metadata, err := inspectContributor(contributor)
|
|
52
|
+
if err != nil {
|
|
53
|
+
fmt.Fprintf(os.Stderr,
|
|
54
|
+
"@ttsc/lint: %v; dropping contributor entry\n",
|
|
55
|
+
err)
|
|
56
|
+
continue
|
|
57
|
+
}
|
|
58
|
+
contributors = append(contributors, metadata)
|
|
59
|
+
}
|
|
38
60
|
sort.SliceStable(contributors, func(i, j int) bool {
|
|
39
|
-
return contributors[i].
|
|
61
|
+
return contributors[i].name < contributors[j].name
|
|
40
62
|
})
|
|
41
63
|
for _, contributor := range contributors {
|
|
42
|
-
name := contributor.
|
|
64
|
+
name := contributor.name
|
|
43
65
|
if name == "" {
|
|
44
66
|
fmt.Fprintln(os.Stderr, "@ttsc/lint: contributor rule with empty name ignored")
|
|
45
67
|
continue
|
|
@@ -50,41 +72,122 @@ func registerContributors() {
|
|
|
50
72
|
name)
|
|
51
73
|
continue
|
|
52
74
|
}
|
|
53
|
-
|
|
54
|
-
|
|
75
|
+
adapter := newContributorAdapter(contributor)
|
|
76
|
+
if contributor.isFormat {
|
|
77
|
+
Register(formatContributorAdapter{adapter})
|
|
55
78
|
continue
|
|
56
79
|
}
|
|
57
|
-
Register(
|
|
80
|
+
Register(adapter)
|
|
81
|
+
}
|
|
82
|
+
registerProjectContributors()
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// contributorMetadata is the immutable host-side view of a public contributor
|
|
86
|
+
// rule. Every contributor-defined metadata method is evaluated exactly once
|
|
87
|
+
// behind inspectContributor's recover barrier so a broken declaration cannot
|
|
88
|
+
// panic later during registry sorting or engine construction.
|
|
89
|
+
type contributorMetadata struct {
|
|
90
|
+
inner rule.Rule
|
|
91
|
+
acceptsOptions bool
|
|
92
|
+
isFormat bool
|
|
93
|
+
name string
|
|
94
|
+
visits []shimast.Kind
|
|
95
|
+
visitsDeclarationFiles bool
|
|
96
|
+
needsTypeChecker bool
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// inspectContributor evaluates the public rule metadata behind a recover
|
|
100
|
+
// barrier. Check itself is protected separately by runRuleCheck; this function
|
|
101
|
+
// covers the startup methods the engine must call before it can dispatch a
|
|
102
|
+
// node. A panicking contributor is rejected as one entry while the rest of the
|
|
103
|
+
// lint registry remains usable.
|
|
104
|
+
func inspectContributor(contributor rule.Rule) (metadata contributorMetadata, err error) {
|
|
105
|
+
defer func() {
|
|
106
|
+
if recovered := recover(); recovered != nil {
|
|
107
|
+
err = fmt.Errorf("contributor %T metadata panicked: %v", contributor, recovered)
|
|
108
|
+
}
|
|
109
|
+
}()
|
|
110
|
+
metadata = contributorMetadata{
|
|
111
|
+
inner: contributor,
|
|
112
|
+
acceptsOptions: true,
|
|
113
|
+
name: contributor.Name(),
|
|
114
|
+
visits: append([]shimast.Kind(nil), contributor.Visits()...),
|
|
115
|
+
visitsDeclarationFiles: true,
|
|
116
|
+
needsTypeChecker: true,
|
|
117
|
+
}
|
|
118
|
+
if formatRule, ok := contributor.(rule.FormatRule); ok {
|
|
119
|
+
metadata.isFormat = formatRule.IsFormat()
|
|
120
|
+
}
|
|
121
|
+
if declarationRule, ok := contributor.(rule.DeclarationFileRule); ok {
|
|
122
|
+
metadata.visitsDeclarationFiles = declarationRule.VisitsDeclarationFiles()
|
|
123
|
+
}
|
|
124
|
+
if typeAware, ok := contributor.(rule.TypeAwareRule); ok {
|
|
125
|
+
metadata.needsTypeChecker = typeAware.NeedsTypeChecker()
|
|
126
|
+
}
|
|
127
|
+
if optionsRule, ok := contributor.(rule.OptionsRule); ok {
|
|
128
|
+
metadata.acceptsOptions = optionsRule.AcceptsTtscLintOptions()
|
|
129
|
+
}
|
|
130
|
+
return metadata, nil
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// newContributorAdapter builds the engine-facing adapter from metadata already
|
|
134
|
+
// evaluated by inspectContributor, so no adapter method re-enters contributor
|
|
135
|
+
// code after startup. This is the only construction path; a zero-value
|
|
136
|
+
// contributorAdapter carries no usable metadata.
|
|
137
|
+
func newContributorAdapter(metadata contributorMetadata) contributorAdapter {
|
|
138
|
+
return contributorAdapter{
|
|
139
|
+
inner: metadata.inner,
|
|
140
|
+
acceptsOptions: metadata.acceptsOptions,
|
|
141
|
+
name: metadata.name,
|
|
142
|
+
visits: metadata.visits,
|
|
143
|
+
visitsDeclarationFiles: metadata.visitsDeclarationFiles,
|
|
144
|
+
needsTypeChecker: metadata.needsTypeChecker,
|
|
58
145
|
}
|
|
59
146
|
}
|
|
60
147
|
|
|
61
148
|
// contributorAdapter wraps a public `rule.Rule` so the engine's
|
|
62
|
-
// `Register` accepts it.
|
|
63
|
-
//
|
|
64
|
-
// into the engine's existing
|
|
149
|
+
// `Register` accepts it. Name, Visits, and declaration-file policy are
|
|
150
|
+
// cached by inspectContributor; Check bridges through a `rule.Context`
|
|
151
|
+
// whose `Reporter` calls back into the engine's existing Context.Report /
|
|
152
|
+
// ReportRange. The
|
|
65
153
|
// public `rule.Context` and the engine's internal `Context` share the
|
|
66
154
|
// same shim AST types, so no wrapping / unwrapping of nodes is needed.
|
|
67
155
|
type contributorAdapter struct {
|
|
68
|
-
inner
|
|
156
|
+
inner rule.Rule
|
|
157
|
+
acceptsOptions bool
|
|
158
|
+
name string
|
|
159
|
+
visits []shimast.Kind
|
|
160
|
+
visitsDeclarationFiles bool
|
|
161
|
+
needsTypeChecker bool
|
|
69
162
|
}
|
|
70
163
|
|
|
71
|
-
//
|
|
72
|
-
//
|
|
73
|
-
//
|
|
164
|
+
// AcceptsTtscLintOptions preserves the public contributor contract:
|
|
165
|
+
// contributors have historically been allowed to decode an arbitrary options
|
|
166
|
+
// blob, so the conservative default is true. A contributor can implement
|
|
167
|
+
// rule.OptionsRule and return false to declare a genuinely optionless rule.
|
|
168
|
+
func (a contributorAdapter) AcceptsTtscLintOptions() bool {
|
|
169
|
+
return a.acceptsOptions
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// NeedsTypeChecker keeps contributor rules on the conservative checker path
|
|
173
|
+
// unless the contributor opts out through the public `rule.TypeAwareRule`
|
|
174
|
+
// marker. The public rule.Context exposes Checker, so the host cannot infer a
|
|
175
|
+
// third-party rule is AST-only — the default is type-aware, and only a rule
|
|
176
|
+
// that explicitly returns false skips the standalone checker and keeps the
|
|
177
|
+
// parallel file walk. The default-true / marker-override policy is applied
|
|
178
|
+
// once in inspectContributor.
|
|
74
179
|
func (a contributorAdapter) NeedsTypeChecker() bool {
|
|
75
|
-
return
|
|
180
|
+
return a.needsTypeChecker
|
|
76
181
|
}
|
|
77
182
|
|
|
78
183
|
// VisitsDeclarationFiles keeps contributor rules running on declaration
|
|
79
184
|
// files unless the contributor opts out through the public
|
|
80
185
|
// `rule.DeclarationFileRule` marker. Same conservative-default reasoning
|
|
81
186
|
// as NeedsTypeChecker: the host cannot infer a third-party rule's grammar
|
|
82
|
-
// shape, and a wrong skip silently loses findings.
|
|
187
|
+
// shape, and a wrong skip silently loses findings. The default-true /
|
|
188
|
+
// marker-override policy is applied once in inspectContributor.
|
|
83
189
|
func (a contributorAdapter) VisitsDeclarationFiles() bool {
|
|
84
|
-
|
|
85
|
-
return dr.VisitsDeclarationFiles()
|
|
86
|
-
}
|
|
87
|
-
return true
|
|
190
|
+
return a.visitsDeclarationFiles
|
|
88
191
|
}
|
|
89
192
|
|
|
90
193
|
// formatContributorAdapter is the FormatRule-tagged variant of
|
|
@@ -98,18 +201,19 @@ type formatContributorAdapter struct {
|
|
|
98
201
|
|
|
99
202
|
func (formatContributorAdapter) IsFormat() bool { return true }
|
|
100
203
|
|
|
101
|
-
func (a contributorAdapter) Name() string { return a.
|
|
102
|
-
func (a contributorAdapter) Visits() []shimast.Kind { return a.
|
|
204
|
+
func (a contributorAdapter) Name() string { return a.name }
|
|
205
|
+
func (a contributorAdapter) Visits() []shimast.Kind { return a.visits }
|
|
103
206
|
func (a contributorAdapter) Check(ctx *Context, node *shimast.Node) {
|
|
104
207
|
if ctx == nil {
|
|
105
208
|
return
|
|
106
209
|
}
|
|
107
|
-
pubCtx := rule.
|
|
210
|
+
pubCtx := rule.NewContextWithProjectResults(
|
|
108
211
|
ctx.File,
|
|
109
212
|
ctx.Checker,
|
|
110
213
|
rule.Severity(ctx.Severity),
|
|
111
214
|
ctx.Options,
|
|
112
215
|
contextReporter{ctx: ctx},
|
|
216
|
+
ctx.projectResults,
|
|
113
217
|
)
|
|
114
218
|
a.inner.Check(pubCtx, node)
|
|
115
219
|
}
|
|
@@ -159,15 +159,16 @@ var declarationFileRuleNames = map[string]bool{
|
|
|
159
159
|
"functional/type-declaration-immutability": true,
|
|
160
160
|
|
|
161
161
|
// unicorn/* rules over file names, comments, identifier naming, and
|
|
162
|
-
// the
|
|
163
|
-
// types.
|
|
164
|
-
"unicorn/
|
|
165
|
-
"unicorn/
|
|
166
|
-
"unicorn/
|
|
167
|
-
"unicorn/
|
|
168
|
-
"unicorn/no-
|
|
169
|
-
"unicorn/no-
|
|
170
|
-
"unicorn/
|
|
171
|
-
"unicorn/
|
|
172
|
-
"unicorn/
|
|
162
|
+
// the literals that appear in enum initializers and literal types
|
|
163
|
+
// (numeric literals, template literal types).
|
|
164
|
+
"unicorn/consistent-template-literal-escape": true,
|
|
165
|
+
"unicorn/empty-brace-spaces": true,
|
|
166
|
+
"unicorn/expiring-todo-comments": true,
|
|
167
|
+
"unicorn/filename-case": true,
|
|
168
|
+
"unicorn/no-abusive-eslint-disable": true,
|
|
169
|
+
"unicorn/no-empty-file": true,
|
|
170
|
+
"unicorn/no-keyword-prefix": true,
|
|
171
|
+
"unicorn/number-literal-case": true,
|
|
172
|
+
"unicorn/numeric-separators-style": true,
|
|
173
|
+
"unicorn/prevent-abbreviations": true,
|
|
173
174
|
}
|
package/linthost/directives.go
CHANGED
|
@@ -98,28 +98,17 @@ func filterInlineDisabledFindingsWithDirectives(file *shimast.SourceFile, findin
|
|
|
98
98
|
}
|
|
99
99
|
filtered := findings[:0]
|
|
100
100
|
for _, finding := range findings {
|
|
101
|
-
if finding == nil || !directives.suppresses(file, finding) {
|
|
101
|
+
if finding == nil || finding.engineFailure || !directives.suppresses(file, finding) {
|
|
102
102
|
filtered = append(filtered, finding)
|
|
103
103
|
}
|
|
104
104
|
}
|
|
105
105
|
return filtered
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
-
// parseLintInlineDirectives scans all comment tokens in
|
|
109
|
-
//
|
|
110
|
-
// per-line and range-style
|
|
111
|
-
//
|
|
112
|
-
// The raw scanner does not split `KindTemplateExpression` on its own:
|
|
113
|
-
// after returning `KindTemplateHead`/`KindTemplateMiddle`, it resumes
|
|
114
|
-
// lexing the substitution as ordinary code, and a later `}` is reported
|
|
115
|
-
// as `KindCloseBraceToken` instead of re-entering the template body.
|
|
116
|
-
// Without intervention the next backtick would open a fresh template
|
|
117
|
-
// scan that swallows the rest of the file (including every disable
|
|
118
|
-
// directive comment) as one runaway unterminated literal. The parser
|
|
119
|
-
// avoids this by calling `ReScanTemplateToken` on the matching `}`;
|
|
120
|
-
// this loop mirrors that behavior with a brace-depth stack so comment
|
|
121
|
-
// positions stay aligned with the source bytes past any template
|
|
122
|
-
// substitution.
|
|
108
|
+
// parseLintInlineDirectives scans all parser-classified comment tokens in
|
|
109
|
+
// `file` (via the shared `forEachCommentToken` loop) for recognized directive
|
|
110
|
+
// markers and returns a structured summary of the per-line and range-style
|
|
111
|
+
// suppressions found.
|
|
123
112
|
func parseLintInlineDirectives(file *shimast.SourceFile) *lintInlineDirectives {
|
|
124
113
|
directives := &lintInlineDirectives{
|
|
125
114
|
lines: make(map[int][]lintDirectiveRules),
|
|
@@ -135,58 +124,11 @@ func parseLintInlineDirectives(file *shimast.SourceFile) *lintInlineDirectives {
|
|
|
135
124
|
if !strings.Contains(text, "-disable") && !strings.Contains(text, "-enable") {
|
|
136
125
|
return directives
|
|
137
126
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
scanner.SetSkipTrivia(false)
|
|
141
|
-
|
|
142
|
-
// templateBraceDepth tracks `{` nesting inside each open template
|
|
143
|
-
// substitution. A zero on top means the next `}` matches the original
|
|
144
|
-
// `${` and must be re-scanned as a template middle/tail token.
|
|
145
|
-
var templateBraceDepth []int
|
|
146
|
-
|
|
147
|
-
scan:
|
|
148
|
-
for {
|
|
149
|
-
kind := scanner.Scan()
|
|
150
|
-
switch kind {
|
|
151
|
-
case shimast.KindEndOfFile:
|
|
152
|
-
break scan
|
|
153
|
-
case shimast.KindTemplateHead, shimast.KindTemplateMiddle:
|
|
154
|
-
// Entering a `${...}` substitution; account for its closing `}`.
|
|
155
|
-
templateBraceDepth = append(templateBraceDepth, 0)
|
|
156
|
-
continue
|
|
157
|
-
case shimast.KindOpenBraceToken:
|
|
158
|
-
if n := len(templateBraceDepth); n > 0 {
|
|
159
|
-
templateBraceDepth[n-1]++
|
|
160
|
-
}
|
|
161
|
-
continue
|
|
162
|
-
case shimast.KindCloseBraceToken:
|
|
163
|
-
n := len(templateBraceDepth)
|
|
164
|
-
if n == 0 {
|
|
165
|
-
continue
|
|
166
|
-
}
|
|
167
|
-
if templateBraceDepth[n-1] > 0 {
|
|
168
|
-
templateBraceDepth[n-1]--
|
|
169
|
-
continue
|
|
170
|
-
}
|
|
171
|
-
// Matching `}` for the original `${`. Pop the substitution and
|
|
172
|
-
// rescan as template; a `KindTemplateMiddle` reopens a new
|
|
173
|
-
// substitution, a `KindTemplateTail` closes the template literal.
|
|
174
|
-
templateBraceDepth = templateBraceDepth[:n-1]
|
|
175
|
-
rescanned := scanner.ReScanTemplateToken(false /*isTaggedTemplate*/)
|
|
176
|
-
if rescanned == shimast.KindTemplateMiddle {
|
|
177
|
-
templateBraceDepth = append(templateBraceDepth, 0)
|
|
178
|
-
}
|
|
179
|
-
continue
|
|
180
|
-
case shimast.KindSingleLineCommentTrivia, shimast.KindMultiLineCommentTrivia:
|
|
181
|
-
default:
|
|
182
|
-
continue
|
|
183
|
-
}
|
|
184
|
-
directive, ok := parseLintDirectiveComment(scanner.TokenText())
|
|
127
|
+
forEachCommentToken(file, func(_ shimast.Kind, start, end int) {
|
|
128
|
+
directive, ok := parseLintDirectiveComment(text[start:end])
|
|
185
129
|
if !ok {
|
|
186
|
-
|
|
130
|
+
return
|
|
187
131
|
}
|
|
188
|
-
start := scanner.TokenStart()
|
|
189
|
-
end := scanner.TokenEnd()
|
|
190
132
|
startLine := shimscanner.GetECMALineOfPosition(file, start)
|
|
191
133
|
endLine := startLine
|
|
192
134
|
if end > start {
|
|
@@ -217,7 +159,7 @@ scan:
|
|
|
217
159
|
directives.records = append(directives.records, lintDirectiveRecord{
|
|
218
160
|
ruleList: append([]string(nil), directive.ruleList...),
|
|
219
161
|
})
|
|
220
|
-
}
|
|
162
|
+
})
|
|
221
163
|
return directives
|
|
222
164
|
}
|
|
223
165
|
|
package/linthost/dispatch.go
CHANGED
|
@@ -8,6 +8,7 @@ package linthost
|
|
|
8
8
|
|
|
9
9
|
import (
|
|
10
10
|
"fmt"
|
|
11
|
+
"io"
|
|
11
12
|
"os"
|
|
12
13
|
)
|
|
13
14
|
|
|
@@ -29,6 +30,39 @@ func Main(args []string) int {
|
|
|
29
30
|
return run(args)
|
|
30
31
|
}
|
|
31
32
|
|
|
33
|
+
// MainWithIO dispatches the browser-owned project commands without consulting
|
|
34
|
+
// process-global stdout or stderr. Native-only mutation and LSP commands retain
|
|
35
|
+
// Main as their CLI entrypoint.
|
|
36
|
+
func MainWithIO(args []string, stdout, stderr io.Writer) int {
|
|
37
|
+
if stdout == nil {
|
|
38
|
+
stdout = io.Discard
|
|
39
|
+
}
|
|
40
|
+
if stderr == nil {
|
|
41
|
+
stderr = io.Discard
|
|
42
|
+
}
|
|
43
|
+
if len(args) == 0 {
|
|
44
|
+
fmt.Fprintln(stderr, "@ttsc/lint: command required (expected check|build|transform|version)")
|
|
45
|
+
return 2
|
|
46
|
+
}
|
|
47
|
+
switch args[0] {
|
|
48
|
+
case "-v", "--version", "version":
|
|
49
|
+
fmt.Fprintf(stdout, "@ttsc/lint %s\n", Version)
|
|
50
|
+
return 0
|
|
51
|
+
case "check":
|
|
52
|
+
registerContributorsOnce()
|
|
53
|
+
return RunCheckWithIO(args[1:], stdout, stderr)
|
|
54
|
+
case "build":
|
|
55
|
+
registerContributorsOnce()
|
|
56
|
+
return RunBuildWithIO(args[1:], stdout, stderr)
|
|
57
|
+
case "transform":
|
|
58
|
+
registerContributorsOnce()
|
|
59
|
+
return RunTransformWithIO(args[1:], stdout, stderr)
|
|
60
|
+
default:
|
|
61
|
+
fmt.Fprintf(stderr, "@ttsc/lint: command %q is unavailable in the browser host\n", args[0])
|
|
62
|
+
return 2
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
32
66
|
// run is the package-local dispatcher invoked by Main and by the in-tree
|
|
33
67
|
// test/command corpus, which exercises end-to-end subcommand routing through
|
|
34
68
|
// the same entry point the CLI uses.
|
|
@@ -47,9 +81,9 @@ func run(args []string) int {
|
|
|
47
81
|
fmt.Fprintf(os.Stderr, "@ttsc/lint: unknown command %q\n", args[0])
|
|
48
82
|
return 2
|
|
49
83
|
}
|
|
50
|
-
// Wire contributor rules into the engine's dispatch table
|
|
51
|
-
// package init has settled. See contrib_adapter.go
|
|
52
|
-
|
|
84
|
+
// Wire init-time contributor rules into the engine's dispatch table once,
|
|
85
|
+
// after every package init has settled. See contrib_adapter.go.
|
|
86
|
+
registerContributorsOnce()
|
|
53
87
|
switch args[0] {
|
|
54
88
|
case "check":
|
|
55
89
|
return RunCheck(args[1:])
|