@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
|
@@ -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.
|
|
@@ -68,6 +79,7 @@ func registerContributors() {
|
|
|
68
79
|
}
|
|
69
80
|
Register(adapter)
|
|
70
81
|
}
|
|
82
|
+
registerProjectContributors()
|
|
71
83
|
}
|
|
72
84
|
|
|
73
85
|
// contributorMetadata is the immutable host-side view of a public contributor
|
|
@@ -76,10 +88,12 @@ func registerContributors() {
|
|
|
76
88
|
// panic later during registry sorting or engine construction.
|
|
77
89
|
type contributorMetadata struct {
|
|
78
90
|
inner rule.Rule
|
|
91
|
+
acceptsOptions bool
|
|
79
92
|
isFormat bool
|
|
80
93
|
name string
|
|
81
94
|
visits []shimast.Kind
|
|
82
95
|
visitsDeclarationFiles bool
|
|
96
|
+
needsTypeChecker bool
|
|
83
97
|
}
|
|
84
98
|
|
|
85
99
|
// inspectContributor evaluates the public rule metadata behind a recover
|
|
@@ -95,9 +109,11 @@ func inspectContributor(contributor rule.Rule) (metadata contributorMetadata, er
|
|
|
95
109
|
}()
|
|
96
110
|
metadata = contributorMetadata{
|
|
97
111
|
inner: contributor,
|
|
112
|
+
acceptsOptions: true,
|
|
98
113
|
name: contributor.Name(),
|
|
99
114
|
visits: append([]shimast.Kind(nil), contributor.Visits()...),
|
|
100
115
|
visitsDeclarationFiles: true,
|
|
116
|
+
needsTypeChecker: true,
|
|
101
117
|
}
|
|
102
118
|
if formatRule, ok := contributor.(rule.FormatRule); ok {
|
|
103
119
|
metadata.isFormat = formatRule.IsFormat()
|
|
@@ -105,6 +121,12 @@ func inspectContributor(contributor rule.Rule) (metadata contributorMetadata, er
|
|
|
105
121
|
if declarationRule, ok := contributor.(rule.DeclarationFileRule); ok {
|
|
106
122
|
metadata.visitsDeclarationFiles = declarationRule.VisitsDeclarationFiles()
|
|
107
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
|
+
}
|
|
108
130
|
return metadata, nil
|
|
109
131
|
}
|
|
110
132
|
|
|
@@ -115,9 +137,11 @@ func inspectContributor(contributor rule.Rule) (metadata contributorMetadata, er
|
|
|
115
137
|
func newContributorAdapter(metadata contributorMetadata) contributorAdapter {
|
|
116
138
|
return contributorAdapter{
|
|
117
139
|
inner: metadata.inner,
|
|
140
|
+
acceptsOptions: metadata.acceptsOptions,
|
|
118
141
|
name: metadata.name,
|
|
119
142
|
visits: metadata.visits,
|
|
120
143
|
visitsDeclarationFiles: metadata.visitsDeclarationFiles,
|
|
144
|
+
needsTypeChecker: metadata.needsTypeChecker,
|
|
121
145
|
}
|
|
122
146
|
}
|
|
123
147
|
|
|
@@ -130,16 +154,30 @@ func newContributorAdapter(metadata contributorMetadata) contributorAdapter {
|
|
|
130
154
|
// same shim AST types, so no wrapping / unwrapping of nodes is needed.
|
|
131
155
|
type contributorAdapter struct {
|
|
132
156
|
inner rule.Rule
|
|
157
|
+
acceptsOptions bool
|
|
133
158
|
name string
|
|
134
159
|
visits []shimast.Kind
|
|
135
160
|
visitsDeclarationFiles bool
|
|
161
|
+
needsTypeChecker bool
|
|
162
|
+
}
|
|
163
|
+
|
|
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
|
|
136
170
|
}
|
|
137
171
|
|
|
138
|
-
// NeedsTypeChecker keeps contributor rules on the
|
|
139
|
-
//
|
|
140
|
-
//
|
|
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.
|
|
141
179
|
func (a contributorAdapter) NeedsTypeChecker() bool {
|
|
142
|
-
return
|
|
180
|
+
return a.needsTypeChecker
|
|
143
181
|
}
|
|
144
182
|
|
|
145
183
|
// VisitsDeclarationFiles keeps contributor rules running on declaration
|
|
@@ -169,12 +207,13 @@ func (a contributorAdapter) Check(ctx *Context, node *shimast.Node) {
|
|
|
169
207
|
if ctx == nil {
|
|
170
208
|
return
|
|
171
209
|
}
|
|
172
|
-
pubCtx := rule.
|
|
210
|
+
pubCtx := rule.NewContextWithProjectResults(
|
|
173
211
|
ctx.File,
|
|
174
212
|
ctx.Checker,
|
|
175
213
|
rule.Severity(ctx.Severity),
|
|
176
214
|
ctx.Options,
|
|
177
215
|
contextReporter{ctx: ctx},
|
|
216
|
+
ctx.projectResults,
|
|
178
217
|
)
|
|
179
218
|
a.inner.Check(pubCtx, node)
|
|
180
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:])
|