lintcn 0.2.0 → 0.4.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/CHANGELOG.md +33 -0
- package/dist/cache.d.ts +1 -1
- package/dist/cache.d.ts.map +1 -1
- package/dist/cache.js +85 -46
- package/dist/codegen.d.ts +4 -9
- package/dist/codegen.d.ts.map +1 -1
- package/dist/codegen.js +27 -506
- package/dist/commands/add.d.ts.map +1 -1
- package/dist/commands/add.js +29 -16
- package/dist/commands/lint.d.ts.map +1 -1
- package/dist/commands/lint.js +2 -5
- package/dist/commands/list.d.ts.map +1 -1
- package/dist/commands/list.js +3 -4
- package/dist/commands/remove.d.ts.map +1 -1
- package/dist/commands/remove.js +2 -5
- package/dist/discover.d.ts.map +1 -1
- package/dist/discover.js +8 -1
- package/dist/hash.d.ts.map +1 -1
- package/dist/hash.js +6 -2
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/paths.d.ts +6 -0
- package/dist/paths.d.ts.map +1 -1
- package/dist/paths.js +23 -1
- package/package.json +2 -1
- package/src/cache.ts +95 -51
- package/src/codegen.ts +27 -512
- package/src/commands/add.ts +34 -19
- package/src/commands/lint.ts +2 -5
- package/src/commands/list.ts +3 -4
- package/src/commands/remove.ts +2 -6
- package/src/discover.ts +10 -1
- package/src/hash.ts +7 -2
- package/src/index.ts +1 -0
- package/src/paths.ts +25 -1
package/dist/codegen.js
CHANGED
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
// Generate Go workspace files for building a custom tsgolint binary.
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
// build/go.work — build workspace in cache dir
|
|
6
|
-
// build/wrapper/go.mod — wrapper module
|
|
7
|
-
// build/wrapper/main.go — entry point with all rules
|
|
2
|
+
// With the fork (remorses/tsgolint) exposing pkg/runner.Run(), codegen is
|
|
3
|
+
// minimal: a 10-line main.go template + go.work with shim replaces.
|
|
4
|
+
// No regex surgery, no file copying, no fragile string manipulation.
|
|
8
5
|
import fs from 'node:fs';
|
|
9
6
|
import path from 'node:path';
|
|
10
|
-
//
|
|
11
|
-
// These redirect
|
|
7
|
+
// Shim modules that need replace directives in go.work.
|
|
8
|
+
// These redirect module paths to local directories inside the tsgolint source.
|
|
12
9
|
const SHIM_MODULES = [
|
|
13
10
|
'ast',
|
|
14
11
|
'bundled',
|
|
@@ -25,87 +22,12 @@ const SHIM_MODULES = [
|
|
|
25
22
|
'vfs/cachedvfs',
|
|
26
23
|
'vfs/osvfs',
|
|
27
24
|
];
|
|
28
|
-
// Built-in tsgolint rules — all 50+ from cmd/tsgolint/main.go.
|
|
29
|
-
// Each entry: [package_path_suffix, exported_var_name]
|
|
30
|
-
const BUILTIN_RULES = [
|
|
31
|
-
['await_thenable', 'AwaitThenableRule'],
|
|
32
|
-
['consistent_return', 'ConsistentReturnRule'],
|
|
33
|
-
['consistent_type_exports', 'ConsistentTypeExportsRule'],
|
|
34
|
-
['dot_notation', 'DotNotationRule'],
|
|
35
|
-
['no_array_delete', 'NoArrayDeleteRule'],
|
|
36
|
-
['no_base_to_string', 'NoBaseToStringRule'],
|
|
37
|
-
['no_confusing_void_expression', 'NoConfusingVoidExpressionRule'],
|
|
38
|
-
['no_deprecated', 'NoDeprecatedRule'],
|
|
39
|
-
['no_duplicate_type_constituents', 'NoDuplicateTypeConstituentsRule'],
|
|
40
|
-
['no_floating_promises', 'NoFloatingPromisesRule'],
|
|
41
|
-
['no_for_in_array', 'NoForInArrayRule'],
|
|
42
|
-
['no_implied_eval', 'NoImpliedEvalRule'],
|
|
43
|
-
['no_meaningless_void_operator', 'NoMeaninglessVoidOperatorRule'],
|
|
44
|
-
['no_misused_promises', 'NoMisusedPromisesRule'],
|
|
45
|
-
['no_misused_spread', 'NoMisusedSpreadRule'],
|
|
46
|
-
['no_mixed_enums', 'NoMixedEnumsRule'],
|
|
47
|
-
['no_redundant_type_constituents', 'NoRedundantTypeConstituentsRule'],
|
|
48
|
-
['no_unnecessary_boolean_literal_compare', 'NoUnnecessaryBooleanLiteralCompareRule'],
|
|
49
|
-
['no_unnecessary_condition', 'NoUnnecessaryConditionRule'],
|
|
50
|
-
['no_unnecessary_qualifier', 'NoUnnecessaryQualifierRule'],
|
|
51
|
-
['no_unnecessary_template_expression', 'NoUnnecessaryTemplateExpressionRule'],
|
|
52
|
-
['no_unnecessary_type_conversion', 'NoUnnecessaryTypeConversionRule'],
|
|
53
|
-
['no_unnecessary_type_arguments', 'NoUnnecessaryTypeArgumentsRule'],
|
|
54
|
-
['no_unnecessary_type_parameters', 'NoUnnecessaryTypeParametersRule'],
|
|
55
|
-
['no_unnecessary_type_assertion', 'NoUnnecessaryTypeAssertionRule'],
|
|
56
|
-
['no_useless_default_assignment', 'NoUselessDefaultAssignmentRule'],
|
|
57
|
-
['no_unsafe_argument', 'NoUnsafeArgumentRule'],
|
|
58
|
-
['no_unsafe_assignment', 'NoUnsafeAssignmentRule'],
|
|
59
|
-
['no_unsafe_call', 'NoUnsafeCallRule'],
|
|
60
|
-
['no_unsafe_enum_comparison', 'NoUnsafeEnumComparisonRule'],
|
|
61
|
-
['no_unsafe_member_access', 'NoUnsafeMemberAccessRule'],
|
|
62
|
-
['no_unsafe_return', 'NoUnsafeReturnRule'],
|
|
63
|
-
['no_unsafe_type_assertion', 'NoUnsafeTypeAssertionRule'],
|
|
64
|
-
['no_unsafe_unary_minus', 'NoUnsafeUnaryMinusRule'],
|
|
65
|
-
['non_nullable_type_assertion_style', 'NonNullableTypeAssertionStyleRule'],
|
|
66
|
-
['only_throw_error', 'OnlyThrowErrorRule'],
|
|
67
|
-
['prefer_find', 'PreferFindRule'],
|
|
68
|
-
['prefer_includes', 'PreferIncludesRule'],
|
|
69
|
-
['prefer_optional_chain', 'PreferOptionalChainRule'],
|
|
70
|
-
['prefer_nullish_coalescing', 'PreferNullishCoalescingRule'],
|
|
71
|
-
['prefer_promise_reject_errors', 'PreferPromiseRejectErrorsRule'],
|
|
72
|
-
['prefer_readonly_parameter_types', 'PreferReadonlyParameterTypesRule'],
|
|
73
|
-
['prefer_regexp_exec', 'PreferRegexpExecRule'],
|
|
74
|
-
['prefer_readonly', 'PreferReadonlyRule'],
|
|
75
|
-
['prefer_reduce_type_parameter', 'PreferReduceTypeParameterRule'],
|
|
76
|
-
['prefer_return_this_type', 'PreferReturnThisTypeRule'],
|
|
77
|
-
['prefer_string_starts_ends_with', 'PreferStringStartsEndsWithRule'],
|
|
78
|
-
['promise_function_async', 'PromiseFunctionAsyncRule'],
|
|
79
|
-
['related_getter_setter_pairs', 'RelatedGetterSetterPairsRule'],
|
|
80
|
-
['require_array_sort_compare', 'RequireArraySortCompareRule'],
|
|
81
|
-
['require_await', 'RequireAwaitRule'],
|
|
82
|
-
['restrict_plus_operands', 'RestrictPlusOperandsRule'],
|
|
83
|
-
['restrict_template_expressions', 'RestrictTemplateExpressionsRule'],
|
|
84
|
-
['return_await', 'ReturnAwaitRule'],
|
|
85
|
-
['strict_boolean_expressions', 'StrictBooleanExpressionsRule'],
|
|
86
|
-
['strict_void_return', 'StrictVoidReturnRule'],
|
|
87
|
-
['switch_exhaustiveness_check', 'SwitchExhaustivenessCheckRule'],
|
|
88
|
-
['unbound_method', 'UnboundMethodRule'],
|
|
89
|
-
['use_unknown_in_catch_callback_variable', 'UseUnknownInCatchCallbackVariableRule'],
|
|
90
|
-
];
|
|
91
25
|
function generateReplaceDirectives(tsgolintRelPath) {
|
|
92
26
|
return SHIM_MODULES.map((mod) => {
|
|
93
27
|
return `\tgithub.com/microsoft/typescript-go/shim/${mod} => ${tsgolintRelPath}/shim/${mod}`;
|
|
94
28
|
}).join('\n');
|
|
95
29
|
}
|
|
96
|
-
|
|
97
|
-
return SHIM_MODULES.map((mod) => {
|
|
98
|
-
return `\tgithub.com/microsoft/typescript-go/shim/${mod} v0.0.0`;
|
|
99
|
-
}).join('\n');
|
|
100
|
-
}
|
|
101
|
-
/** Generate .lintcn/go.work and .lintcn/go.mod for editor/gopls support.
|
|
102
|
-
*
|
|
103
|
-
* Key learnings from testing:
|
|
104
|
-
* - Module name MUST be a child path of github.com/typescript-eslint/tsgolint
|
|
105
|
-
* so Go allows importing internal/ packages across the module boundary.
|
|
106
|
-
* - go.work must `use` both .tsgolint AND .tsgolint/typescript-go since
|
|
107
|
-
* tsgolint's own go.work (which does this) is ignored by the outer workspace.
|
|
108
|
-
* - go.mod should be minimal (no requires) — the workspace resolves everything. */
|
|
30
|
+
/** Generate .lintcn/go.work and .lintcn/go.mod for editor/gopls support. */
|
|
109
31
|
export function generateEditorGoFiles(lintcnDir) {
|
|
110
32
|
const goWork = `go 1.26
|
|
111
33
|
|
|
@@ -119,7 +41,8 @@ replace (
|
|
|
119
41
|
${generateReplaceDirectives('./.tsgolint')}
|
|
120
42
|
)
|
|
121
43
|
`;
|
|
122
|
-
|
|
44
|
+
// No child-path hack needed — pkg/ is public, any module name works
|
|
45
|
+
const goMod = `module lintcn-rules
|
|
123
46
|
|
|
124
47
|
go 1.26
|
|
125
48
|
`;
|
|
@@ -136,7 +59,9 @@ go.sum
|
|
|
136
59
|
fs.writeFileSync(gitignorePath, gitignore);
|
|
137
60
|
}
|
|
138
61
|
}
|
|
139
|
-
/** Generate build workspace
|
|
62
|
+
/** Generate build workspace for compiling the custom binary.
|
|
63
|
+
* With pkg/runner.Run(), the generated main.go is a static template —
|
|
64
|
+
* no regex surgery or file copying needed. */
|
|
140
65
|
export function generateBuildWorkspace({ buildDir, tsgolintDir, lintcnDir, rules, }) {
|
|
141
66
|
fs.mkdirSync(path.join(buildDir, 'wrapper'), { recursive: true });
|
|
142
67
|
// symlink tsgolint source
|
|
@@ -151,7 +76,7 @@ export function generateBuildWorkspace({ buildDir, tsgolintDir, lintcnDir, rules
|
|
|
151
76
|
fs.rmSync(rulesLink, { recursive: true });
|
|
152
77
|
}
|
|
153
78
|
fs.symlinkSync(path.resolve(lintcnDir), rulesLink);
|
|
154
|
-
// go.work
|
|
79
|
+
// go.work
|
|
155
80
|
const goWork = `go 1.26
|
|
156
81
|
|
|
157
82
|
use (
|
|
@@ -166,442 +91,38 @@ ${generateReplaceDirectives('./tsgolint')}
|
|
|
166
91
|
)
|
|
167
92
|
`;
|
|
168
93
|
fs.writeFileSync(path.join(buildDir, 'go.work'), goWork);
|
|
169
|
-
// wrapper/go.mod —
|
|
170
|
-
const wrapperGoMod = `module
|
|
94
|
+
// wrapper/go.mod — simple module name, no child-path hack needed
|
|
95
|
+
const wrapperGoMod = `module lintcn-wrapper
|
|
171
96
|
|
|
172
97
|
go 1.26
|
|
173
|
-
|
|
174
|
-
require (
|
|
175
|
-
\tgithub.com/typescript-eslint/tsgolint v0.0.0
|
|
176
|
-
\tgithub.com/typescript-eslint/tsgolint/lintcn-rules v0.0.0
|
|
177
|
-
)
|
|
178
98
|
`;
|
|
179
99
|
fs.writeFileSync(path.join(buildDir, 'wrapper', 'go.mod'), wrapperGoMod);
|
|
180
|
-
// wrapper/main.go
|
|
100
|
+
// wrapper/main.go — simple template, no regex or string surgery
|
|
181
101
|
const mainGo = generateMainGo(rules);
|
|
182
102
|
fs.writeFileSync(path.join(buildDir, 'wrapper', 'main.go'), mainGo);
|
|
183
103
|
}
|
|
184
|
-
/** Generate
|
|
185
|
-
* This is
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
const tsgolintPkg = 'github.com/typescript-eslint/tsgolint';
|
|
190
|
-
// built-in rule imports
|
|
191
|
-
const builtinImports = BUILTIN_RULES.map(([pkg]) => {
|
|
192
|
-
return `\t"${tsgolintPkg}/internal/rules/${pkg}"`;
|
|
193
|
-
}).join('\n');
|
|
194
|
-
// built-in rule entries
|
|
195
|
-
const builtinEntries = BUILTIN_RULES.map(([pkg, varName]) => {
|
|
196
|
-
return `\t${pkg}.${varName},`;
|
|
104
|
+
/** Generate a minimal main.go that imports user rules and calls runner.Run().
|
|
105
|
+
* This is a static template — no copying or patching of tsgolint source. */
|
|
106
|
+
function generateMainGo(rules) {
|
|
107
|
+
const ruleEntries = rules.map((r) => {
|
|
108
|
+
return `\t\tlintcn.${r.varName},`;
|
|
197
109
|
}).join('\n');
|
|
198
|
-
// custom rule entries (all in package lintcn via single import)
|
|
199
|
-
const customEntries = customRules.map((r) => {
|
|
200
|
-
return `\tlintcn.${r.varName},`;
|
|
201
|
-
}).join('\n');
|
|
202
|
-
// only add lintcn import if there are custom rules
|
|
203
|
-
const lintcnImport = customRules.length > 0 ? '\n\tlintcn "github.com/typescript-eslint/tsgolint/lintcn-rules"' : '';
|
|
204
110
|
return `// Code generated by lintcn. DO NOT EDIT.
|
|
205
111
|
package main
|
|
206
112
|
|
|
207
113
|
import (
|
|
208
|
-
\t"bufio"
|
|
209
|
-
\t"flag"
|
|
210
|
-
\t"fmt"
|
|
211
|
-
\t"math"
|
|
212
114
|
\t"os"
|
|
213
|
-
\t"runtime"
|
|
214
|
-
\t"runtime/pprof"
|
|
215
|
-
\t"runtime/trace"
|
|
216
|
-
\t"slices"
|
|
217
|
-
\t"strconv"
|
|
218
|
-
\t"strings"
|
|
219
|
-
\t"sync"
|
|
220
|
-
\t"time"
|
|
221
|
-
\t"unicode"
|
|
222
|
-
|
|
223
|
-
\t"${tsgolintPkg}/internal/diagnostic"
|
|
224
|
-
\t"${tsgolintPkg}/internal/linter"
|
|
225
|
-
\t"${tsgolintPkg}/internal/rule"
|
|
226
|
-
\t"${tsgolintPkg}/internal/utils"
|
|
227
115
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
\
|
|
231
|
-
\t"github.com/microsoft/typescript-go/shim/bundled"
|
|
232
|
-
\t"github.com/microsoft/typescript-go/shim/core"
|
|
233
|
-
\t"github.com/microsoft/typescript-go/shim/scanner"
|
|
234
|
-
\t"github.com/microsoft/typescript-go/shim/tspath"
|
|
235
|
-
\t"github.com/microsoft/typescript-go/shim/vfs/cachedvfs"
|
|
236
|
-
\t"github.com/microsoft/typescript-go/shim/vfs/osvfs"
|
|
116
|
+
\t"github.com/typescript-eslint/tsgolint/pkg/rule"
|
|
117
|
+
\t"github.com/typescript-eslint/tsgolint/pkg/runner"
|
|
118
|
+
\tlintcn "lintcn-rules"
|
|
237
119
|
)
|
|
238
120
|
|
|
239
|
-
var allRules = []rule.Rule{
|
|
240
|
-
${builtinEntries}
|
|
241
|
-
${customEntries}
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
var allRulesByName = make(map[string]rule.Rule, len(allRules))
|
|
245
|
-
|
|
246
|
-
func init() {
|
|
247
|
-
\tfor _, rule := range allRules {
|
|
248
|
-
\t\tallRulesByName[rule.Name] = rule
|
|
249
|
-
\t}
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
// Below is copied from tsgolint's cmd/tsgolint/main.go.
|
|
253
|
-
// We cannot import it directly because main packages are not importable in Go.
|
|
254
|
-
|
|
255
|
-
func recordTrace(traceOut string) (func(), error) {
|
|
256
|
-
\tif traceOut != "" {
|
|
257
|
-
\t\tf, err := os.Create(traceOut)
|
|
258
|
-
\t\tif err != nil {
|
|
259
|
-
\t\t\treturn nil, fmt.Errorf("error creating trace file: %w", err)
|
|
260
|
-
\t\t}
|
|
261
|
-
\t\ttrace.Start(f)
|
|
262
|
-
\t\treturn func() {
|
|
263
|
-
\t\t\ttrace.Stop()
|
|
264
|
-
\t\t\tf.Close()
|
|
265
|
-
\t\t}, nil
|
|
266
|
-
\t}
|
|
267
|
-
\treturn func() {}, nil
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
func recordCpuprof(cpuprofOut string) (func(), error) {
|
|
271
|
-
\tif cpuprofOut != "" {
|
|
272
|
-
\t\tf, err := os.Create(cpuprofOut)
|
|
273
|
-
\t\tif err != nil {
|
|
274
|
-
\t\t\treturn nil, fmt.Errorf("error creating cpuprof file: %w", err)
|
|
275
|
-
\t\t}
|
|
276
|
-
\t\terr = pprof.StartCPUProfile(f)
|
|
277
|
-
\t\tif err != nil {
|
|
278
|
-
\t\t\treturn nil, fmt.Errorf("error starting cpu profiling: %w", err)
|
|
279
|
-
\t\t}
|
|
280
|
-
\t\treturn func() {
|
|
281
|
-
\t\t\tpprof.StopCPUProfile()
|
|
282
|
-
\t\t\tf.Close()
|
|
283
|
-
\t\t}, nil
|
|
284
|
-
\t}
|
|
285
|
-
\treturn func() {}, nil
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
const spaces = " "
|
|
289
|
-
|
|
290
|
-
func printDiagnostic(d rule.RuleDiagnostic, w *bufio.Writer, comparePathOptions tspath.ComparePathsOptions) {
|
|
291
|
-
\tdiagnosticStart := d.Range.Pos()
|
|
292
|
-
\tdiagnosticEnd := d.Range.End()
|
|
293
|
-
\tdiagnosticStartLine, diagnosticStartColumn := scanner.GetECMALineAndUTF16CharacterOfPosition(d.SourceFile, diagnosticStart)
|
|
294
|
-
\tdiagnosticEndline, _ := scanner.GetECMALineAndUTF16CharacterOfPosition(d.SourceFile, diagnosticEnd)
|
|
295
|
-
\tlineMap := d.SourceFile.ECMALineMap()
|
|
296
|
-
\ttext := d.SourceFile.Text()
|
|
297
|
-
\tcodeboxStartLine := max(diagnosticStartLine-1, 0)
|
|
298
|
-
\tcodeboxEndLine := min(diagnosticEndline+1, len(lineMap)-1)
|
|
299
|
-
\tcodeboxStart := scanner.GetECMAPositionOfLineAndUTF16Character(d.SourceFile, codeboxStartLine, 0)
|
|
300
|
-
\tvar codeboxEndColumn int
|
|
301
|
-
\tif codeboxEndLine == len(lineMap)-1 {
|
|
302
|
-
\t\tcodeboxEndColumn = len(text) - int(lineMap[len(lineMap)-1])
|
|
303
|
-
\t} else {
|
|
304
|
-
\t\tcodeboxEndColumn = int(lineMap[codeboxEndLine+1]-lineMap[codeboxEndLine]) - 1
|
|
305
|
-
\t}
|
|
306
|
-
\tcodeboxEnd := scanner.GetECMAPositionOfLineAndUTF16Character(d.SourceFile, codeboxEndLine, core.UTF16Offset(codeboxEndColumn))
|
|
307
|
-
\tw.Write([]byte{' ', 0x1b, '[', '7', 'm', 0x1b, '[', '1', 'm', 0x1b, '[', '3', '8', ';', '5', ';', '3', '7', 'm', ' '})
|
|
308
|
-
\tw.WriteString(d.RuleName)
|
|
309
|
-
\tw.WriteString(" \\x1b[0m — ")
|
|
310
|
-
\tmessageLineStart := 0
|
|
311
|
-
\tfor i, char := range d.Message.Description {
|
|
312
|
-
\t\tif char == '\\n' {
|
|
313
|
-
\t\t\tw.WriteString(d.Message.Description[messageLineStart : i+1])
|
|
314
|
-
\t\t\tmessageLineStart = i + 1
|
|
315
|
-
\t\t\tw.WriteString(" \\x1b[2m│\\x1b[0m")
|
|
316
|
-
\t\t\tw.WriteString(spaces[:len(d.RuleName)+1])
|
|
317
|
-
\t\t}
|
|
318
|
-
\t}
|
|
319
|
-
\tif messageLineStart <= len(d.Message.Description) {
|
|
320
|
-
\t\tw.WriteString(d.Message.Description[messageLineStart:len(d.Message.Description)])
|
|
321
|
-
\t}
|
|
322
|
-
\tw.WriteString("\\n \\x1b[2m╭─┴──────────(\\x1b[0m \\x1b[3m\\x1b[38;5;117m")
|
|
323
|
-
\tw.WriteString(tspath.ConvertToRelativePath(d.SourceFile.FileName(), comparePathOptions))
|
|
324
|
-
\tw.WriteByte(':')
|
|
325
|
-
\tw.WriteString(strconv.Itoa(diagnosticStartLine + 1))
|
|
326
|
-
\tw.WriteByte(':')
|
|
327
|
-
\tw.WriteString(strconv.Itoa(int(diagnosticStartColumn) + 1))
|
|
328
|
-
\tw.WriteString("\\x1b[0m \\x1b[2m)─────\\x1b[0m\\n")
|
|
329
|
-
\tindentSize := math.MaxInt
|
|
330
|
-
\tline := codeboxStartLine
|
|
331
|
-
\tlineIndentCalculated := false
|
|
332
|
-
\tlastNonSpaceIndex := -1
|
|
333
|
-
\tlineStarts := make([]int, 13)
|
|
334
|
-
\tlineEnds := make([]int, 13)
|
|
335
|
-
\tif codeboxEndLine-codeboxStartLine >= len(lineEnds) {
|
|
336
|
-
\t\tw.WriteString(" \\x1b[2m│\\x1b[0m Error range is too big. Skipping code block printing.\\n \\x1b[2m╰────────────────────────────────\\x1b[0m\\n\\n")
|
|
337
|
-
\t\treturn
|
|
338
|
-
\t}
|
|
339
|
-
\tfor i, char := range text[codeboxStart:codeboxEnd] {
|
|
340
|
-
\t\tif char == '\\n' {
|
|
341
|
-
\t\t\tif line != codeboxEndLine {
|
|
342
|
-
\t\t\t\tlineIndentCalculated = false
|
|
343
|
-
\t\t\t\tlineEnds[line-codeboxStartLine] = lastNonSpaceIndex - int(lineMap[line]) + codeboxStart
|
|
344
|
-
\t\t\t\tlastNonSpaceIndex = -1
|
|
345
|
-
\t\t\t\tline++
|
|
346
|
-
\t\t\t}
|
|
347
|
-
\t\t\tcontinue
|
|
348
|
-
\t\t}
|
|
349
|
-
\t\tif !lineIndentCalculated && !unicode.IsSpace(char) {
|
|
350
|
-
\t\t\tlineIndentCalculated = true
|
|
351
|
-
\t\t\tlineStarts[line-codeboxStartLine] = i - int(lineMap[line]) + codeboxStart
|
|
352
|
-
\t\t\tindentSize = min(indentSize, lineStarts[line-codeboxStartLine])
|
|
353
|
-
\t\t}
|
|
354
|
-
\t\tif lineIndentCalculated && !unicode.IsSpace(char) {
|
|
355
|
-
\t\t\tlastNonSpaceIndex = i + 1
|
|
356
|
-
\t\t}
|
|
357
|
-
\t}
|
|
358
|
-
\tif line == codeboxEndLine {
|
|
359
|
-
\t\tlineEnds[line-codeboxStartLine] = lastNonSpaceIndex - int(lineMap[line]) + codeboxStart
|
|
360
|
-
\t}
|
|
361
|
-
\tdiagnosticHighlightActive := false
|
|
362
|
-
\tlastLineNumber := strconv.Itoa(codeboxEndLine + 1)
|
|
363
|
-
\tfor line := codeboxStartLine; line <= codeboxEndLine; line++ {
|
|
364
|
-
\t\tw.WriteString(" \\x1b[2m│ ")
|
|
365
|
-
\t\tif line == codeboxEndLine {
|
|
366
|
-
\t\t\tw.WriteString(lastLineNumber)
|
|
367
|
-
\t\t} else {
|
|
368
|
-
\t\t\tnumber := strconv.Itoa(line + 1)
|
|
369
|
-
\t\t\tif len(number) < len(lastLineNumber) {
|
|
370
|
-
\t\t\t\tw.WriteByte(' ')
|
|
371
|
-
\t\t\t}
|
|
372
|
-
\t\t\tw.WriteString(number)
|
|
373
|
-
\t\t}
|
|
374
|
-
\t\tw.WriteString(" │\\x1b[0m ")
|
|
375
|
-
\t\tlineTextStart := int(lineMap[line]) + indentSize
|
|
376
|
-
\t\tunderlineStart := max(lineTextStart, int(lineMap[line])+lineStarts[line-codeboxStartLine])
|
|
377
|
-
\t\tunderlineEnd := underlineStart
|
|
378
|
-
\t\tlineTextEnd := max(int(lineMap[line])+lineEnds[line-codeboxStartLine], lineTextStart)
|
|
379
|
-
\t\tif diagnosticHighlightActive {
|
|
380
|
-
\t\t\tunderlineEnd = lineTextEnd
|
|
381
|
-
\t\t} else if int(lineMap[line]) <= diagnosticStart && (line == len(lineMap) || diagnosticStart < int(lineMap[line+1])) {
|
|
382
|
-
\t\t\tunderlineStart = min(max(lineTextStart, diagnosticStart), lineTextEnd)
|
|
383
|
-
\t\t\tunderlineEnd = lineTextEnd
|
|
384
|
-
\t\t\tdiagnosticHighlightActive = true
|
|
385
|
-
\t\t}
|
|
386
|
-
\t\tif int(lineMap[line]) <= diagnosticEnd && (line == len(lineMap) || diagnosticEnd < int(lineMap[line+1])) {
|
|
387
|
-
\t\t\tunderlineEnd = min(max(underlineStart, diagnosticEnd), lineTextEnd)
|
|
388
|
-
\t\t\tdiagnosticHighlightActive = false
|
|
389
|
-
\t\t}
|
|
390
|
-
\t\tif underlineStart != underlineEnd {
|
|
391
|
-
\t\t\tw.WriteString(text[lineTextStart:underlineStart])
|
|
392
|
-
\t\t\tw.Write([]byte{
|
|
393
|
-
\t\t\t\t0x1b, '[', '4', 'm',
|
|
394
|
-
\t\t\t\t0x1b, '[', '4', ':', '3', 'm',
|
|
395
|
-
\t\t\t\t0x1b, '[', '5', '8', ':', '5', ':', '1', '6', '0', 'm',
|
|
396
|
-
\t\t\t\t0x1b, '[', '3', '8', ';', '5', ';', '1', '6', '0', 'm',
|
|
397
|
-
\t\t\t\t0x1b, '[', '2', '2', ';', '4', '9', 'm',
|
|
398
|
-
\t\t\t})
|
|
399
|
-
\t\t\tw.WriteString(text[underlineStart:underlineEnd])
|
|
400
|
-
\t\t\tw.Write([]byte{0x1b, '[', '0', 'm'})
|
|
401
|
-
\t\t\tw.WriteString(text[underlineEnd:lineTextEnd])
|
|
402
|
-
\t\t} else if lineTextStart != lineTextEnd {
|
|
403
|
-
\t\t\tw.WriteString(text[lineTextStart:lineTextEnd])
|
|
404
|
-
\t\t}
|
|
405
|
-
\t\tw.WriteByte('\\n')
|
|
406
|
-
\t}
|
|
407
|
-
\tw.WriteString(" \\x1b[2m╰────────────────────────────────\\x1b[0m\\n\\n")
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
const usage = \` lintcn - type-aware TypeScript linter with custom rules
|
|
411
|
-
|
|
412
|
-
Usage:
|
|
413
|
-
lintcn-binary [OPTIONS]
|
|
414
|
-
|
|
415
|
-
Options:
|
|
416
|
-
--tsconfig PATH Which tsconfig to use. Defaults to tsconfig.json.
|
|
417
|
-
--list-files List matched files
|
|
418
|
-
-h, --help Show help
|
|
419
|
-
\`
|
|
420
|
-
|
|
421
|
-
func runMain() int {
|
|
422
|
-
\tflag.Usage = func() { fmt.Fprint(os.Stderr, usage) }
|
|
423
|
-
\tvar (
|
|
424
|
-
\t\thelp bool
|
|
425
|
-
\t\ttsconfig string
|
|
426
|
-
\t\tlistFiles bool
|
|
427
|
-
\t\ttraceOut string
|
|
428
|
-
\t\tcpuprofOut string
|
|
429
|
-
\t\tsingleThreaded bool
|
|
430
|
-
\t)
|
|
431
|
-
\tflag.StringVar(&tsconfig, "tsconfig", "", "which tsconfig to use")
|
|
432
|
-
\tflag.BoolVar(&listFiles, "list-files", false, "list matched files")
|
|
433
|
-
\tflag.BoolVar(&help, "help", false, "show help")
|
|
434
|
-
\tflag.BoolVar(&help, "h", false, "show help")
|
|
435
|
-
\tflag.StringVar(&traceOut, "trace", "", "file to put trace to")
|
|
436
|
-
\tflag.StringVar(&cpuprofOut, "cpuprof", "", "file to put cpu profiling to")
|
|
437
|
-
\tflag.BoolVar(&singleThreaded, "singleThreaded", false, "run in single threaded mode")
|
|
438
|
-
\tflag.Parse()
|
|
439
|
-
\tif help {
|
|
440
|
-
\t\tflag.Usage()
|
|
441
|
-
\t\treturn 0
|
|
442
|
-
\t}
|
|
443
|
-
\ttimeBefore := time.Now()
|
|
444
|
-
\tif done, err := recordTrace(traceOut); err != nil {
|
|
445
|
-
\t\tos.Stderr.WriteString(err.Error())
|
|
446
|
-
\t\treturn 1
|
|
447
|
-
\t} else {
|
|
448
|
-
\t\tdefer done()
|
|
449
|
-
\t}
|
|
450
|
-
\tif done, err := recordCpuprof(cpuprofOut); err != nil {
|
|
451
|
-
\t\tos.Stderr.WriteString(err.Error())
|
|
452
|
-
\t\treturn 1
|
|
453
|
-
\t} else {
|
|
454
|
-
\t\tdefer done()
|
|
455
|
-
\t}
|
|
456
|
-
\tcurrentDirectory, err := os.Getwd()
|
|
457
|
-
\tif err != nil {
|
|
458
|
-
\t\tfmt.Fprintf(os.Stderr, "error getting current directory: %v\\n", err)
|
|
459
|
-
\t\treturn 1
|
|
460
|
-
\t}
|
|
461
|
-
\tcurrentDirectory = tspath.NormalizePath(currentDirectory)
|
|
462
|
-
\tfs := bundled.WrapFS(cachedvfs.From(osvfs.FS()))
|
|
463
|
-
\tvar configFileName string
|
|
464
|
-
\tif tsconfig == "" {
|
|
465
|
-
\t\tconfigFileName = tspath.ResolvePath(currentDirectory, "tsconfig.json")
|
|
466
|
-
\t\tif !fs.FileExists(configFileName) {
|
|
467
|
-
\t\t\tfs = utils.NewOverlayVFS(fs, map[string]string{
|
|
468
|
-
\t\t\t\tconfigFileName: "{}",
|
|
469
|
-
\t\t\t})
|
|
470
|
-
\t\t}
|
|
471
|
-
\t} else {
|
|
472
|
-
\t\tconfigFileName = tspath.ResolvePath(currentDirectory, tsconfig)
|
|
473
|
-
\t\tif !fs.FileExists(configFileName) {
|
|
474
|
-
\t\t\tfmt.Fprintf(os.Stderr, "error: tsconfig %q doesn't exist", tsconfig)
|
|
475
|
-
\t\t\treturn 1
|
|
476
|
-
\t\t}
|
|
477
|
-
\t}
|
|
478
|
-
\tcurrentDirectory = tspath.GetDirectoryPath(configFileName)
|
|
479
|
-
\thost := utils.CreateCompilerHost(currentDirectory, fs)
|
|
480
|
-
\tcomparePathOptions := tspath.ComparePathsOptions{
|
|
481
|
-
\t\tCurrentDirectory: host.GetCurrentDirectory(),
|
|
482
|
-
\t\tUseCaseSensitiveFileNames: host.FS().UseCaseSensitiveFileNames(),
|
|
483
|
-
\t}
|
|
484
|
-
\tprogram, _, err := utils.CreateProgram(singleThreaded, fs, currentDirectory, configFileName, host, false)
|
|
485
|
-
\tif err != nil {
|
|
486
|
-
\t\tfmt.Fprintf(os.Stderr, "error creating TS program: %v", err)
|
|
487
|
-
\t\treturn 1
|
|
488
|
-
\t}
|
|
489
|
-
\tif program == nil {
|
|
490
|
-
\t\tfmt.Fprintf(os.Stderr, "error creating TS program")
|
|
491
|
-
\t\treturn 1
|
|
492
|
-
\t}
|
|
493
|
-
\tfiles := []*ast.SourceFile{}
|
|
494
|
-
\tcwdPath := string(tspath.ToPath("", currentDirectory, program.Host().FS().UseCaseSensitiveFileNames()).EnsureTrailingDirectorySeparator())
|
|
495
|
-
\tvar matchedFiles strings.Builder
|
|
496
|
-
\tfor _, file := range program.SourceFiles() {
|
|
497
|
-
\t\tp := string(file.Path())
|
|
498
|
-
\t\tif strings.Contains(p, "/node_modules/") {
|
|
499
|
-
\t\t\tcontinue
|
|
500
|
-
\t\t}
|
|
501
|
-
\t\tif fileName, matched := strings.CutPrefix(p, cwdPath); matched {
|
|
502
|
-
\t\t\tif listFiles {
|
|
503
|
-
\t\t\t\tmatchedFiles.WriteString("Found file: ")
|
|
504
|
-
\t\t\t\tmatchedFiles.WriteString(fileName)
|
|
505
|
-
\t\t\t\tmatchedFiles.WriteByte('\\n')
|
|
506
|
-
\t\t\t}
|
|
507
|
-
\t\t\tfiles = append(files, file)
|
|
508
|
-
\t\t}
|
|
509
|
-
\t}
|
|
510
|
-
\tif listFiles {
|
|
511
|
-
\t\tos.Stdout.WriteString(matchedFiles.String())
|
|
512
|
-
\t}
|
|
513
|
-
\tslices.SortFunc(files, func(a *ast.SourceFile, b *ast.SourceFile) int {
|
|
514
|
-
\t\treturn len(b.Text()) - len(a.Text())
|
|
515
|
-
\t})
|
|
516
|
-
\tvar wg sync.WaitGroup
|
|
517
|
-
\tdiagnosticsChan := make(chan rule.RuleDiagnostic, 4096)
|
|
518
|
-
\terrorsCount := 0
|
|
519
|
-
\twg.Go(func() {
|
|
520
|
-
\t\tw := bufio.NewWriterSize(os.Stdout, 4096*100)
|
|
521
|
-
\t\tdefer w.Flush()
|
|
522
|
-
\t\tfor d := range diagnosticsChan {
|
|
523
|
-
\t\t\terrorsCount++
|
|
524
|
-
\t\t\tif errorsCount == 1 {
|
|
525
|
-
\t\t\t\tw.WriteByte('\\n')
|
|
526
|
-
\t\t\t}
|
|
527
|
-
\t\t\tprintDiagnostic(d, w, comparePathOptions)
|
|
528
|
-
\t\t\tif w.Available() < 4096 {
|
|
529
|
-
\t\t\t\tw.Flush()
|
|
530
|
-
\t\t\t}
|
|
531
|
-
\t\t}
|
|
532
|
-
\t})
|
|
533
|
-
\terr = linter.RunLinterOnProgram(
|
|
534
|
-
\t\tutils.GetLogLevel(),
|
|
535
|
-
\t\tprogram,
|
|
536
|
-
\t\tfiles,
|
|
537
|
-
\t\truntime.GOMAXPROCS(0),
|
|
538
|
-
\t\tfunc(sourceFile *ast.SourceFile) []linter.ConfiguredRule {
|
|
539
|
-
\t\t\treturn utils.Map(allRules, func(r rule.Rule) linter.ConfiguredRule {
|
|
540
|
-
\t\t\t\treturn linter.ConfiguredRule{
|
|
541
|
-
\t\t\t\t\tName: r.Name,
|
|
542
|
-
\t\t\t\t\tRun: func(ctx rule.RuleContext) rule.RuleListeners {
|
|
543
|
-
\t\t\t\t\t\treturn r.Run(ctx, nil)
|
|
544
|
-
\t\t\t\t\t},
|
|
545
|
-
\t\t\t\t}
|
|
546
|
-
\t\t\t})
|
|
547
|
-
\t\t},
|
|
548
|
-
\t\tfunc(d rule.RuleDiagnostic) {
|
|
549
|
-
\t\t\tdiagnosticsChan <- d
|
|
550
|
-
\t\t},
|
|
551
|
-
\t\tfunc(d diagnostic.Internal) {},
|
|
552
|
-
\t\tlinter.Fixes{
|
|
553
|
-
\t\t\tFix: true,
|
|
554
|
-
\t\t\tFixSuggestions: true,
|
|
555
|
-
\t\t},
|
|
556
|
-
\t\tlinter.TypeErrors{
|
|
557
|
-
\t\t\tReportSyntactic: false,
|
|
558
|
-
\t\t\tReportSemantic: false,
|
|
559
|
-
\t\t},
|
|
560
|
-
\t)
|
|
561
|
-
\tclose(diagnosticsChan)
|
|
562
|
-
\tif err != nil {
|
|
563
|
-
\t\tfmt.Fprintf(os.Stderr, "error running linter: %v\\n", err)
|
|
564
|
-
\t\treturn 1
|
|
565
|
-
\t}
|
|
566
|
-
\twg.Wait()
|
|
567
|
-
\terrorsColor := "\\x1b[1m"
|
|
568
|
-
\tif errorsCount == 0 {
|
|
569
|
-
\t\terrorsColor = "\\x1b[1;32m"
|
|
570
|
-
\t}
|
|
571
|
-
\terrorsText := "errors"
|
|
572
|
-
\tif errorsCount == 1 {
|
|
573
|
-
\t\terrorsText = "error"
|
|
574
|
-
\t}
|
|
575
|
-
\tfilesText := "files"
|
|
576
|
-
\tif len(files) == 1 {
|
|
577
|
-
\t\tfilesText = "file"
|
|
578
|
-
\t}
|
|
579
|
-
\trulesText := "rules"
|
|
580
|
-
\tif len(allRules) == 1 {
|
|
581
|
-
\t\trulesText = "rule"
|
|
582
|
-
\t}
|
|
583
|
-
\tthreadsCount := 1
|
|
584
|
-
\tif !singleThreaded {
|
|
585
|
-
\t\tthreadsCount = runtime.GOMAXPROCS(0)
|
|
586
|
-
\t}
|
|
587
|
-
\tfmt.Fprintf(
|
|
588
|
-
\t\tos.Stdout,
|
|
589
|
-
\t\t"Found %v%v\\x1b[0m %v \\x1b[2m(linted \\x1b[1m%v\\x1b[22m\\x1b[2m %v with \\x1b[1m%v\\x1b[22m\\x1b[2m %v in \\x1b[1m%v\\x1b[22m\\x1b[2m using \\x1b[1m%v\\x1b[22m\\x1b[2m threads)\\n",
|
|
590
|
-
\t\terrorsColor,
|
|
591
|
-
\t\terrorsCount,
|
|
592
|
-
\t\terrorsText,
|
|
593
|
-
\t\tlen(files),
|
|
594
|
-
\t\tfilesText,
|
|
595
|
-
\t\tlen(allRules),
|
|
596
|
-
\t\trulesText,
|
|
597
|
-
\t\ttime.Since(timeBefore).Round(time.Millisecond),
|
|
598
|
-
\t\tthreadsCount,
|
|
599
|
-
\t)
|
|
600
|
-
\treturn 0
|
|
601
|
-
}
|
|
602
|
-
|
|
603
121
|
func main() {
|
|
604
|
-
\
|
|
122
|
+
\trules := []rule.Rule{
|
|
123
|
+
${ruleEntries}
|
|
124
|
+
\t}
|
|
125
|
+
\tos.Exit(runner.Run(rules, os.Args[1:]))
|
|
605
126
|
}
|
|
606
127
|
`;
|
|
607
128
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"AA+EA,wBAAsB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAqDxD"}
|
package/dist/commands/add.js
CHANGED
|
@@ -6,32 +6,48 @@ import path from 'node:path';
|
|
|
6
6
|
import { getLintcnDir } from "../paths.js";
|
|
7
7
|
import { generateEditorGoFiles } from "../codegen.js";
|
|
8
8
|
import { ensureTsgolintSource, DEFAULT_TSGOLINT_VERSION } from "../cache.js";
|
|
9
|
+
/** Convert GitHub blob URLs to raw.githubusercontent.com.
|
|
10
|
+
* Handles branch names containing slashes (e.g. feature/x) by splitting
|
|
11
|
+
* on /blob/ then finding the file path from the end (must end in .go). */
|
|
9
12
|
function normalizeGithubUrl(url) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const [, owner, repo, branch, filePath] = blobMatch;
|
|
14
|
-
return `https://raw.githubusercontent.com/${owner}/${repo}/${branch}/${filePath}`;
|
|
13
|
+
const blobSplit = url.match(/^(https?:\/\/github\.com\/[^/]+\/[^/]+)\/blob\/(.+)$/);
|
|
14
|
+
if (!blobSplit) {
|
|
15
|
+
return url;
|
|
15
16
|
}
|
|
16
|
-
|
|
17
|
+
const [, repoUrl, refAndPath] = blobSplit;
|
|
18
|
+
// repoUrl = "https://github.com/owner/repo"
|
|
19
|
+
// refAndPath = "feature/x/rules/my_rule.go" or "main/rules/my_rule.go"
|
|
20
|
+
// Extract owner/repo from repoUrl
|
|
21
|
+
const repoMatch = repoUrl.match(/github\.com\/([^/]+)\/([^/]+)$/);
|
|
22
|
+
if (!repoMatch) {
|
|
23
|
+
return url;
|
|
24
|
+
}
|
|
25
|
+
const [, owner, repo] = repoMatch;
|
|
26
|
+
// For raw.githubusercontent.com, the format is owner/repo/ref/path.
|
|
27
|
+
// We can pass refAndPath directly since GitHub resolves it.
|
|
28
|
+
return `https://raw.githubusercontent.com/${owner}/${repo}/${refAndPath}`;
|
|
17
29
|
}
|
|
18
30
|
function deriveTestUrl(rawUrl) {
|
|
19
31
|
return rawUrl.replace(/\.go$/, '_test.go');
|
|
20
32
|
}
|
|
21
33
|
async function fetchFile(url) {
|
|
34
|
+
const response = await fetch(url);
|
|
35
|
+
if (!response.ok) {
|
|
36
|
+
throw new Error(`Failed to fetch ${url}: ${response.status} ${response.statusText}`);
|
|
37
|
+
}
|
|
38
|
+
return response.text();
|
|
39
|
+
}
|
|
40
|
+
async function tryFetchFile(url) {
|
|
22
41
|
try {
|
|
23
|
-
|
|
24
|
-
if (!response.ok) {
|
|
25
|
-
return null;
|
|
26
|
-
}
|
|
27
|
-
return await response.text();
|
|
42
|
+
return await fetchFile(url);
|
|
28
43
|
}
|
|
29
44
|
catch {
|
|
30
45
|
return null;
|
|
31
46
|
}
|
|
32
47
|
}
|
|
33
48
|
function rewritePackageName(content) {
|
|
34
|
-
// Rewrite first package declaration to package lintcn
|
|
49
|
+
// Rewrite first package declaration to package lintcn.
|
|
50
|
+
// Only matches before the first import or func to avoid touching comments.
|
|
35
51
|
return content.replace(/^package\s+\w+/m, 'package lintcn');
|
|
36
52
|
}
|
|
37
53
|
function ensureSourceComment(content, sourceUrl) {
|
|
@@ -56,9 +72,6 @@ export async function addRule(url) {
|
|
|
56
72
|
const rawUrl = normalizeGithubUrl(url);
|
|
57
73
|
console.log(`Fetching ${rawUrl}...`);
|
|
58
74
|
const content = await fetchFile(rawUrl);
|
|
59
|
-
if (!content) {
|
|
60
|
-
throw new Error(`Could not fetch rule from ${rawUrl}`);
|
|
61
|
-
}
|
|
62
75
|
// validate it looks like a Go file with a rule
|
|
63
76
|
if (!content.includes('rule.Rule')) {
|
|
64
77
|
console.warn('Warning: no rule.Rule reference found in this file. Are you sure this is a tsgolint rule?');
|
|
@@ -82,7 +95,7 @@ export async function addRule(url) {
|
|
|
82
95
|
console.log(`Added ${fileName}`);
|
|
83
96
|
// try to fetch matching test file
|
|
84
97
|
const testUrl = deriveTestUrl(rawUrl);
|
|
85
|
-
const testContent = await
|
|
98
|
+
const testContent = await tryFetchFile(testUrl);
|
|
86
99
|
if (testContent) {
|
|
87
100
|
const testFileName = fileName.replace(/\.go$/, '_test.go');
|
|
88
101
|
const testProcessed = rewritePackageName(testContent);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lint.d.ts","sourceRoot":"","sources":["../../src/commands/lint.ts"],"names":[],"mappings":"AAuBA,wBAAsB,WAAW,CAAC,EAChC,OAAO,EACP,eAAe,GAChB,EAAE;IACD,OAAO,EAAE,OAAO,CAAA;IAChB,eAAe,EAAE,MAAM,CAAA;CACxB,GAAG,OAAO,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"lint.d.ts","sourceRoot":"","sources":["../../src/commands/lint.ts"],"names":[],"mappings":"AAuBA,wBAAsB,WAAW,CAAC,EAChC,OAAO,EACP,eAAe,GAChB,EAAE;IACD,OAAO,EAAE,OAAO,CAAA;IAChB,eAAe,EAAE,MAAM,CAAA;CACxB,GAAG,OAAO,CAAC,MAAM,CAAC,CAiDlB;AAED,wBAAsB,IAAI,CAAC,EACzB,OAAO,EACP,eAAe,EACf,eAAe,GAChB,EAAE;IACD,OAAO,EAAE,OAAO,CAAA;IAChB,eAAe,EAAE,MAAM,CAAA;IACvB,eAAe,EAAE,MAAM,EAAE,CAAA;CAC1B,GAAG,OAAO,CAAC,MAAM,CAAC,CAkBlB"}
|