@ttsc/lint 0.12.3 → 0.13.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/lib/defaultFormat.d.ts +10 -11
- package/lib/defaultFormat.js +10 -11
- package/lib/defaultFormat.js.map +1 -1
- package/lib/index.js +233 -135
- package/lib/index.js.map +1 -1
- package/lib/structures/ITtscLintConfig.d.ts +2 -2
- package/lib/structures/ITtscLintFormatConfig.d.ts +53 -55
- package/lib/structures/ITtscLintPluginConfig.d.ts +10 -77
- package/lib/structures/ITtscLintPluginMeta.d.ts +9 -1
- package/lib/structures/TtscLintRule.d.ts +10 -1
- package/lib/structures/TtscLintRuleMap.d.ts +2 -2
- package/lib/structures/TtscLintRuleOptions.d.ts +14 -0
- package/linthost/ast_helpers.go +80 -11
- package/linthost/compile.go +116 -112
- package/linthost/config.go +647 -687
- package/linthost/config_format.go +272 -247
- package/linthost/contrib_adapter.go +7 -0
- package/linthost/directives.go +116 -0
- package/linthost/dispatch.go +33 -33
- package/linthost/engine.go +156 -43
- package/linthost/fix.go +47 -27
- package/linthost/flags_gen.go +31 -0
- package/linthost/format.go +119 -3
- package/linthost/host.go +115 -5
- package/linthost/print_dispatch.go +128 -28
- package/linthost/print_doc.go +23 -0
- package/linthost/print_engine.go +168 -4
- package/linthost/print_nodes_array.go +17 -7
- package/linthost/print_nodes_call.go +138 -20
- package/linthost/print_nodes_function.go +353 -0
- package/linthost/print_nodes_imports.go +46 -29
- package/linthost/print_nodes_list.go +86 -5
- package/linthost/print_nodes_object.go +56 -11
- package/linthost/rules_arrays.go +5 -2
- package/linthost/rules_debugger.go +3 -2
- package/linthost/rules_dupes.go +7 -4
- package/linthost/rules_empty.go +3 -2
- package/linthost/rules_escape.go +35 -3
- package/linthost/rules_eval.go +3 -0
- package/linthost/rules_finally.go +11 -0
- package/linthost/rules_format_jsdoc.go +7 -0
- package/linthost/rules_format_print_width.go +270 -15
- package/linthost/rules_format_quotes.go +3 -0
- package/linthost/rules_format_sort_imports.go +4 -0
- package/linthost/rules_gap.go +75 -3
- package/linthost/rules_imports.go +5 -7
- package/linthost/rules_logic.go +75 -5
- package/linthost/rules_loops.go +4 -0
- package/linthost/rules_misc.go +4 -2
- package/linthost/rules_params.go +7 -11
- package/linthost/rules_problems.go +89 -22
- package/linthost/rules_promise.go +15 -0
- package/linthost/rules_protos.go +3 -2
- package/linthost/rules_self.go +6 -0
- package/linthost/rules_strings.go +10 -0
- package/linthost/rules_suggestions.go +174 -9
- package/linthost/rules_throw.go +2 -0
- package/linthost/rules_ts.go +13 -0
- package/linthost/rules_ts_extra.go +25 -8
- package/linthost/rules_var.go +15 -2
- package/package.json +3 -3
- package/plugin/main.go +4 -4
- package/rule/astutil/astutil.go +12 -0
- package/rule/rule.go +123 -123
- package/src/defaultFormat.ts +10 -11
- package/src/index.ts +257 -168
- package/src/structures/ITtscLintConfig.ts +2 -2
- package/src/structures/ITtscLintFormatConfig.ts +53 -55
- package/src/structures/ITtscLintPluginConfig.ts +10 -83
- package/src/structures/ITtscLintPluginMeta.ts +9 -1
- package/src/structures/TtscLintRule.ts +10 -1
- package/src/structures/TtscLintRuleMap.ts +17 -18
- package/src/structures/TtscLintRuleOptions.ts +15 -0
- package/linthost/eslint_runtime.go +0 -320
|
@@ -1,320 +0,0 @@
|
|
|
1
|
-
package linthost
|
|
2
|
-
|
|
3
|
-
import (
|
|
4
|
-
"encoding/json"
|
|
5
|
-
"fmt"
|
|
6
|
-
"os"
|
|
7
|
-
"os/exec"
|
|
8
|
-
"path/filepath"
|
|
9
|
-
"strings"
|
|
10
|
-
"unicode/utf8"
|
|
11
|
-
|
|
12
|
-
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
13
|
-
shimdw "github.com/microsoft/typescript-go/shim/diagnosticwriter"
|
|
14
|
-
)
|
|
15
|
-
|
|
16
|
-
type eslintRuntimeProvider interface {
|
|
17
|
-
ExternalConfigPath() string
|
|
18
|
-
WantsESLintRuntime() bool
|
|
19
|
-
RequiresESLintRuntime() bool
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
type eslintRuntimeOutput struct {
|
|
23
|
-
Missing bool `json:"missing"`
|
|
24
|
-
Fixed int `json:"fixed"`
|
|
25
|
-
Results []eslintRuntimeFile `json:"results"`
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
type eslintRuntimeFile struct {
|
|
29
|
-
FilePath string `json:"filePath"`
|
|
30
|
-
Messages []eslintRuntimeMessage `json:"messages"`
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
type eslintRuntimeMessage struct {
|
|
34
|
-
RuleID string `json:"ruleId"`
|
|
35
|
-
Severity int `json:"severity"`
|
|
36
|
-
Message string `json:"message"`
|
|
37
|
-
Line int `json:"line"`
|
|
38
|
-
Column int `json:"column"`
|
|
39
|
-
EndLine int `json:"endLine"`
|
|
40
|
-
EndColumn int `json:"endColumn"`
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
func runExternalESLintDiagnostics(
|
|
44
|
-
resolver RuleResolver,
|
|
45
|
-
cwd string,
|
|
46
|
-
files []*shimast.SourceFile,
|
|
47
|
-
) ([]*shimdw.LintDiagnostic, bool, error) {
|
|
48
|
-
provider, ok := resolver.(eslintRuntimeProvider)
|
|
49
|
-
if !ok || !provider.WantsESLintRuntime() {
|
|
50
|
-
return nil, false, nil
|
|
51
|
-
}
|
|
52
|
-
configPath := provider.ExternalConfigPath()
|
|
53
|
-
if configPath == "" {
|
|
54
|
-
return nil, false, nil
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
fileNames := make([]string, 0, len(files))
|
|
58
|
-
byPath := make(map[string]*shimast.SourceFile, len(files))
|
|
59
|
-
for _, file := range files {
|
|
60
|
-
if file == nil || file.IsDeclarationFile {
|
|
61
|
-
continue
|
|
62
|
-
}
|
|
63
|
-
name := file.FileName()
|
|
64
|
-
if !filepath.IsAbs(name) {
|
|
65
|
-
name = filepath.Join(cwd, name)
|
|
66
|
-
}
|
|
67
|
-
if abs, err := filepath.Abs(name); err == nil {
|
|
68
|
-
name = abs
|
|
69
|
-
}
|
|
70
|
-
fileNames = append(fileNames, name)
|
|
71
|
-
byPath[filepath.ToSlash(name)] = file
|
|
72
|
-
}
|
|
73
|
-
if len(fileNames) == 0 {
|
|
74
|
-
return nil, true, nil
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
payload, err := json.Marshal(fileNames)
|
|
78
|
-
if err != nil {
|
|
79
|
-
return nil, false, fmt.Errorf("@ttsc/lint: encode ESLint file list: %w", err)
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
output, err := runExternalESLint(cwd, configPath, string(payload))
|
|
83
|
-
if err != nil {
|
|
84
|
-
return nil, false, err
|
|
85
|
-
}
|
|
86
|
-
if output.Missing {
|
|
87
|
-
if provider.RequiresESLintRuntime() {
|
|
88
|
-
return nil, false, fmt.Errorf("@ttsc/lint: ESLint runtime is required by %s; install eslint in the project or replace runtime-only config features", configPath)
|
|
89
|
-
}
|
|
90
|
-
return nil, false, nil
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
diagnostics := make([]*shimdw.LintDiagnostic, 0)
|
|
94
|
-
for _, result := range output.Results {
|
|
95
|
-
file := byPath[filepath.ToSlash(result.FilePath)]
|
|
96
|
-
if file == nil {
|
|
97
|
-
continue
|
|
98
|
-
}
|
|
99
|
-
for _, msg := range result.Messages {
|
|
100
|
-
if msg.Severity == 0 {
|
|
101
|
-
continue
|
|
102
|
-
}
|
|
103
|
-
ruleID := strings.TrimSpace(msg.RuleID)
|
|
104
|
-
if ruleID == "" {
|
|
105
|
-
ruleID = "eslint"
|
|
106
|
-
}
|
|
107
|
-
category := shimdw.LintCategoryWarning
|
|
108
|
-
if msg.Severity >= 2 {
|
|
109
|
-
category = shimdw.LintCategoryError
|
|
110
|
-
}
|
|
111
|
-
pos := positionOfESLintLocation(file.Text(), msg.Line, msg.Column)
|
|
112
|
-
end := positionOfESLintLocation(file.Text(), msg.EndLine, msg.EndColumn)
|
|
113
|
-
if end <= pos {
|
|
114
|
-
end = pos + 1
|
|
115
|
-
}
|
|
116
|
-
diagnostics = append(diagnostics, shimdw.NewLintDiagnostic(
|
|
117
|
-
file,
|
|
118
|
-
pos,
|
|
119
|
-
end,
|
|
120
|
-
ruleCode(ruleID),
|
|
121
|
-
category,
|
|
122
|
-
fmt.Sprintf("[%s] %s", ruleID, msg.Message),
|
|
123
|
-
))
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
return diagnostics, true, nil
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
func runExternalESLint(cwd, configPath, fileListJSON string) (*eslintRuntimeOutput, error) {
|
|
130
|
-
return runExternalESLintWithMode(cwd, configPath, fileListJSON, false)
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
func runExternalESLintFixes(
|
|
134
|
-
resolver RuleResolver,
|
|
135
|
-
cwd string,
|
|
136
|
-
files []*shimast.SourceFile,
|
|
137
|
-
) (int, error) {
|
|
138
|
-
provider, ok := resolver.(eslintRuntimeProvider)
|
|
139
|
-
if !ok || !provider.WantsESLintRuntime() {
|
|
140
|
-
return 0, nil
|
|
141
|
-
}
|
|
142
|
-
configPath := provider.ExternalConfigPath()
|
|
143
|
-
if configPath == "" {
|
|
144
|
-
return 0, nil
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
fileNames := make([]string, 0, len(files))
|
|
148
|
-
for _, file := range files {
|
|
149
|
-
if file == nil || file.IsDeclarationFile {
|
|
150
|
-
continue
|
|
151
|
-
}
|
|
152
|
-
name := file.FileName()
|
|
153
|
-
if !filepath.IsAbs(name) {
|
|
154
|
-
name = filepath.Join(cwd, name)
|
|
155
|
-
}
|
|
156
|
-
if abs, err := filepath.Abs(name); err == nil {
|
|
157
|
-
name = abs
|
|
158
|
-
}
|
|
159
|
-
fileNames = append(fileNames, name)
|
|
160
|
-
}
|
|
161
|
-
if len(fileNames) == 0 {
|
|
162
|
-
return 0, nil
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
payload, err := json.Marshal(fileNames)
|
|
166
|
-
if err != nil {
|
|
167
|
-
return 0, fmt.Errorf("@ttsc/lint: encode ESLint file list: %w", err)
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
output, err := runExternalESLintWithMode(cwd, configPath, string(payload), true)
|
|
171
|
-
if err != nil {
|
|
172
|
-
return 0, err
|
|
173
|
-
}
|
|
174
|
-
if output.Missing {
|
|
175
|
-
if provider.RequiresESLintRuntime() {
|
|
176
|
-
return 0, fmt.Errorf("@ttsc/lint: ESLint runtime is required by %s; install eslint in the project or replace runtime-only config features", configPath)
|
|
177
|
-
}
|
|
178
|
-
return 0, nil
|
|
179
|
-
}
|
|
180
|
-
return output.Fixed, nil
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
func runExternalESLintWithMode(cwd, configPath, fileListJSON string, fix bool) (*eslintRuntimeOutput, error) {
|
|
184
|
-
node := os.Getenv("TTSC_NODE_BINARY")
|
|
185
|
-
if node == "" {
|
|
186
|
-
node = "node"
|
|
187
|
-
}
|
|
188
|
-
mode := "check"
|
|
189
|
-
if fix {
|
|
190
|
-
mode = "fix"
|
|
191
|
-
}
|
|
192
|
-
cmd := exec.Command(node, "-e", externalESLintRunnerScript, cwd, configPath, fileListJSON, mode)
|
|
193
|
-
cmd.Env = nodeConfigLoaderEnv(configPath)
|
|
194
|
-
cmd.Dir = cwd
|
|
195
|
-
raw, err := cmd.Output()
|
|
196
|
-
if err != nil {
|
|
197
|
-
stderr := ""
|
|
198
|
-
if exit, ok := err.(*exec.ExitError); ok {
|
|
199
|
-
stderr = strings.TrimSpace(string(exit.Stderr))
|
|
200
|
-
}
|
|
201
|
-
if stderr != "" {
|
|
202
|
-
return nil, fmt.Errorf("@ttsc/lint: run ESLint config %s: %s", configPath, stderr)
|
|
203
|
-
}
|
|
204
|
-
return nil, fmt.Errorf("@ttsc/lint: run ESLint config %s: %w", configPath, err)
|
|
205
|
-
}
|
|
206
|
-
var output eslintRuntimeOutput
|
|
207
|
-
if err := json.Unmarshal(raw, &output); err != nil {
|
|
208
|
-
return nil, fmt.Errorf("@ttsc/lint: parse ESLint output for %s: %w", configPath, err)
|
|
209
|
-
}
|
|
210
|
-
return &output, nil
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
func positionOfESLintLocation(text string, line, column int) int {
|
|
214
|
-
if line <= 0 {
|
|
215
|
-
line = 1
|
|
216
|
-
}
|
|
217
|
-
if column <= 0 {
|
|
218
|
-
column = 1
|
|
219
|
-
}
|
|
220
|
-
lineStart := 0
|
|
221
|
-
currentLine := 1
|
|
222
|
-
for i := 0; i < len(text) && currentLine < line; {
|
|
223
|
-
r, size := utf8.DecodeRuneInString(text[i:])
|
|
224
|
-
if r == '\n' {
|
|
225
|
-
currentLine++
|
|
226
|
-
lineStart = i + size
|
|
227
|
-
}
|
|
228
|
-
i += size
|
|
229
|
-
}
|
|
230
|
-
targetUTF16 := column - 1
|
|
231
|
-
seenUTF16 := 0
|
|
232
|
-
for i := lineStart; i < len(text); {
|
|
233
|
-
if seenUTF16 >= targetUTF16 {
|
|
234
|
-
return i
|
|
235
|
-
}
|
|
236
|
-
r, size := utf8.DecodeRuneInString(text[i:])
|
|
237
|
-
if r == '\n' || r == '\r' {
|
|
238
|
-
return i
|
|
239
|
-
}
|
|
240
|
-
if r > 0xFFFF {
|
|
241
|
-
seenUTF16 += 2
|
|
242
|
-
} else {
|
|
243
|
-
seenUTF16++
|
|
244
|
-
}
|
|
245
|
-
i += size
|
|
246
|
-
}
|
|
247
|
-
return len(text)
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
const externalESLintRunnerScript = `
|
|
251
|
-
const { createRequire } = require("node:module");
|
|
252
|
-
const path = require("node:path");
|
|
253
|
-
|
|
254
|
-
(async () => {
|
|
255
|
-
const cwd = process.argv[1];
|
|
256
|
-
const configPath = process.argv[2];
|
|
257
|
-
const files = JSON.parse(process.argv[3]);
|
|
258
|
-
const shouldFix = process.argv[4] === "fix";
|
|
259
|
-
const requireFromProject = createRequire(path.join(cwd, "package.json"));
|
|
260
|
-
let eslintPath;
|
|
261
|
-
try {
|
|
262
|
-
eslintPath = requireFromProject.resolve("eslint");
|
|
263
|
-
} catch (error) {
|
|
264
|
-
if (error && error.code === "MODULE_NOT_FOUND") {
|
|
265
|
-
process.stdout.write(JSON.stringify({ missing: true, results: [] }));
|
|
266
|
-
return;
|
|
267
|
-
}
|
|
268
|
-
throw error;
|
|
269
|
-
}
|
|
270
|
-
const eslintModule = requireFromProject(eslintPath);
|
|
271
|
-
|
|
272
|
-
const ESLintCtor = typeof eslintModule.loadESLint === "function"
|
|
273
|
-
? await eslintModule.loadESLint({ useFlatConfig: true })
|
|
274
|
-
: eslintModule.ESLint ?? eslintModule.default?.ESLint ?? eslintModule.default;
|
|
275
|
-
|
|
276
|
-
if (typeof ESLintCtor !== "function") {
|
|
277
|
-
throw new Error("installed eslint package does not export ESLint or loadESLint");
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
const eslint = new ESLintCtor({
|
|
281
|
-
cwd,
|
|
282
|
-
overrideConfigFile: configPath,
|
|
283
|
-
fix: shouldFix,
|
|
284
|
-
ignore: true,
|
|
285
|
-
warnIgnored: false,
|
|
286
|
-
});
|
|
287
|
-
const results = await eslint.lintFiles(files);
|
|
288
|
-
if (shouldFix) {
|
|
289
|
-
const outputFixes =
|
|
290
|
-
ESLintCtor.outputFixes ||
|
|
291
|
-
eslintModule.ESLint?.outputFixes ||
|
|
292
|
-
eslintModule.default?.ESLint?.outputFixes;
|
|
293
|
-
if (typeof outputFixes !== "function") {
|
|
294
|
-
throw new Error("installed eslint package does not expose ESLint.outputFixes");
|
|
295
|
-
}
|
|
296
|
-
await outputFixes.call(ESLintCtor, results);
|
|
297
|
-
}
|
|
298
|
-
process.stdout.write(JSON.stringify({
|
|
299
|
-
missing: false,
|
|
300
|
-
fixed: shouldFix
|
|
301
|
-
? results.filter((result) => typeof result.output === "string").length
|
|
302
|
-
: 0,
|
|
303
|
-
results: results.map((result) => ({
|
|
304
|
-
filePath: result.filePath,
|
|
305
|
-
messages: result.messages.map((message) => ({
|
|
306
|
-
ruleId: message.ruleId || "eslint",
|
|
307
|
-
severity: message.severity,
|
|
308
|
-
message: message.message,
|
|
309
|
-
line: message.line || 1,
|
|
310
|
-
column: message.column || 1,
|
|
311
|
-
endLine: message.endLine || message.line || 1,
|
|
312
|
-
endColumn: message.endColumn || message.column || 1,
|
|
313
|
-
})),
|
|
314
|
-
})),
|
|
315
|
-
}));
|
|
316
|
-
})().catch((error) => {
|
|
317
|
-
process.stderr.write(error && error.stack ? error.stack : String(error));
|
|
318
|
-
process.exit(1);
|
|
319
|
-
});
|
|
320
|
-
`
|