@ttsc/lint 0.28.5 → 0.29.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 +2 -0
- package/linthost/check_serve.go +7 -6
- package/linthost/compile.go +50 -44
- package/linthost/fix.go +8 -7
- package/linthost/host.go +24 -3
- package/linthost/lsp.go +16 -14
- package/linthost/project_engine.go +16 -7
- package/linthost/serve.go +8 -6
- package/package.json +2 -2
- package/rule/project.go +22 -1
package/README.md
CHANGED
|
@@ -1185,6 +1185,8 @@ func init() { rule.RegisterProject(noCycles{}) }
|
|
|
1185
1185
|
|
|
1186
1186
|
Each project rule runs once per loaded Program, before file rules. `ctx.Identity` includes the invocation cwd, logical and physical config paths and roots, an optional explicit project root, the plugin-config origin, and a lifecycle id. `Report` marks the rule failed and emits one project finding; `Fail` marks it failed without a finding. Later file rules can call `ctx.ProjectResult(name)` and distinguish `absent`, `off`, `not_evaluated`, `passed`, and `failed`.
|
|
1187
1187
|
|
|
1188
|
+
`ctx.ReportSeverity(rule.SeverityWarn, message)` overrides the level of one project finding. An off rule or off finding remains silent. A warning still marks the project result failed, while only an error fails the command. Snapshots retain each finding's severity, and duplicate messages keep the strongest reported level. Hosts implementing only `ProjectReporter` receive the message at the rule's configured level; `ProjectSeverityReporter` is the optional extension for individual levels.
|
|
1189
|
+
|
|
1188
1190
|
When a project rule reads local files outside the TypeScript Program, implement `rule.ProjectInputRule` so watch and editor hosts can observe exactly those inputs:
|
|
1189
1191
|
|
|
1190
1192
|
```go
|
package/linthost/check_serve.go
CHANGED
|
@@ -220,12 +220,13 @@ func (s *residentCheckState) run(
|
|
|
220
220
|
opts.cwd,
|
|
221
221
|
opts.tsconfig,
|
|
222
222
|
loadProgramOptions{
|
|
223
|
-
forceNoEmit:
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
223
|
+
forceNoEmit: true,
|
|
224
|
+
semanticConfigPath: opts.semanticConfigPath,
|
|
225
|
+
needsRuleChecker: engine.NeedsTypeChecker(),
|
|
226
|
+
singleThreaded: opts.singleThreaded,
|
|
227
|
+
checkers: opts.checkers,
|
|
228
|
+
tsgoArgs: opts.tsgoArgs,
|
|
229
|
+
projectIdentity: opts.projectIdentity,
|
|
229
230
|
},
|
|
230
231
|
)
|
|
231
232
|
if err != nil {
|
package/linthost/compile.go
CHANGED
|
@@ -74,6 +74,7 @@ func RunTransform(args []string) int {
|
|
|
74
74
|
|
|
75
75
|
// RunTransformWithIO runs transform with invocation-owned output streams.
|
|
76
76
|
func RunTransformWithIO(args []string, stdout, stderr io.Writer) int {
|
|
77
|
+
semanticConfigPath := os.Getenv(semanticConfigPathEnv)
|
|
77
78
|
fs := flag.NewFlagSet("transform", flag.ContinueOnError)
|
|
78
79
|
fs.SetOutput(stderr)
|
|
79
80
|
file := fs.String("file", "", "absolute or cwd-relative path of the .ts file to transform")
|
|
@@ -122,12 +123,13 @@ func RunTransformWithIO(args []string, stdout, stderr io.Writer) int {
|
|
|
122
123
|
engine.SetSerial(*singleThreaded)
|
|
123
124
|
|
|
124
125
|
prog, parseDiags, err := loadProgram(resolvedCwd, *tsconfig, loadProgramOptions{
|
|
125
|
-
forceEmit:
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
126
|
+
forceEmit: true,
|
|
127
|
+
semanticConfigPath: semanticConfigPath,
|
|
128
|
+
needsRuleChecker: engine.NeedsTypeChecker(),
|
|
129
|
+
singleThreaded: *singleThreaded,
|
|
130
|
+
checkers: *checkers,
|
|
131
|
+
tsgoArgs: tsgoArgs,
|
|
132
|
+
projectIdentity: projectIdentity,
|
|
131
133
|
})
|
|
132
134
|
if err != nil {
|
|
133
135
|
fmt.Fprintf(stderr, "@ttsc/lint: %v\n", err)
|
|
@@ -201,21 +203,22 @@ func RunTransformWithIO(args []string, stdout, stderr io.Writer) int {
|
|
|
201
203
|
}
|
|
202
204
|
|
|
203
205
|
type subcommandOpts struct {
|
|
204
|
-
cwd
|
|
205
|
-
tsconfig
|
|
206
|
-
pluginsJSON
|
|
207
|
-
emit
|
|
208
|
-
noEmit
|
|
209
|
-
quiet
|
|
210
|
-
verbose
|
|
211
|
-
diagnostics
|
|
212
|
-
outDir
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
206
|
+
cwd string
|
|
207
|
+
tsconfig string
|
|
208
|
+
pluginsJSON string
|
|
209
|
+
emit bool
|
|
210
|
+
noEmit bool
|
|
211
|
+
quiet bool
|
|
212
|
+
verbose bool
|
|
213
|
+
diagnostics bool
|
|
214
|
+
outDir string
|
|
215
|
+
semanticConfigPath string
|
|
216
|
+
singleThreaded bool
|
|
217
|
+
checkers int
|
|
218
|
+
tsgoArgs []string
|
|
219
|
+
projectIdentity publicrule.ProjectIdentity
|
|
220
|
+
stdout io.Writer
|
|
221
|
+
stderr io.Writer
|
|
219
222
|
}
|
|
220
223
|
|
|
221
224
|
// parseSubcommandFlags parses the shared flag set used by the `check`,
|
|
@@ -226,6 +229,7 @@ func parseSubcommandFlags(name string, args []string) (*subcommandOpts, error) {
|
|
|
226
229
|
}
|
|
227
230
|
|
|
228
231
|
func parseSubcommandFlagsWithIO(name string, args []string, stdout, stderr io.Writer) (*subcommandOpts, error) {
|
|
232
|
+
semanticConfigPath := os.Getenv(semanticConfigPathEnv)
|
|
229
233
|
if stdout == nil {
|
|
230
234
|
stdout = io.Discard
|
|
231
235
|
}
|
|
@@ -267,21 +271,22 @@ func parseSubcommandFlagsWithIO(name string, args []string, stdout, stderr io.Wr
|
|
|
267
271
|
return nil, err
|
|
268
272
|
}
|
|
269
273
|
return &subcommandOpts{
|
|
270
|
-
cwd:
|
|
271
|
-
tsconfig:
|
|
272
|
-
pluginsJSON:
|
|
273
|
-
emit:
|
|
274
|
-
noEmit:
|
|
275
|
-
quiet:
|
|
276
|
-
verbose:
|
|
277
|
-
diagnostics:
|
|
278
|
-
outDir:
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
274
|
+
cwd: resolvedCwd,
|
|
275
|
+
tsconfig: *tsconfig,
|
|
276
|
+
pluginsJSON: *pluginsJSON,
|
|
277
|
+
emit: *emit,
|
|
278
|
+
noEmit: *noEmit,
|
|
279
|
+
quiet: *quiet,
|
|
280
|
+
verbose: *verbose,
|
|
281
|
+
diagnostics: *diagnostics || *extendedDiagnostics,
|
|
282
|
+
outDir: *outDir,
|
|
283
|
+
semanticConfigPath: semanticConfigPath,
|
|
284
|
+
singleThreaded: *singleThreaded,
|
|
285
|
+
checkers: *checkers,
|
|
286
|
+
tsgoArgs: tsgoArgs,
|
|
287
|
+
projectIdentity: projectIdentity,
|
|
288
|
+
stdout: stdout,
|
|
289
|
+
stderr: stderr,
|
|
285
290
|
}, nil
|
|
286
291
|
}
|
|
287
292
|
|
|
@@ -332,14 +337,15 @@ func runProject(opts *subcommandOpts) int {
|
|
|
332
337
|
engine.SetSerial(opts.singleThreaded)
|
|
333
338
|
|
|
334
339
|
prog, parseDiags, err := loadProgram(opts.cwd, opts.tsconfig, loadProgramOptions{
|
|
335
|
-
forceEmit:
|
|
336
|
-
forceNoEmit:
|
|
337
|
-
outDir:
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
340
|
+
forceEmit: opts.emit,
|
|
341
|
+
forceNoEmit: opts.noEmit,
|
|
342
|
+
outDir: opts.outDir,
|
|
343
|
+
semanticConfigPath: opts.semanticConfigPath,
|
|
344
|
+
needsRuleChecker: engine.NeedsTypeChecker(),
|
|
345
|
+
singleThreaded: opts.singleThreaded,
|
|
346
|
+
checkers: opts.checkers,
|
|
347
|
+
tsgoArgs: opts.tsgoArgs,
|
|
348
|
+
projectIdentity: opts.projectIdentity,
|
|
343
349
|
})
|
|
344
350
|
if err != nil {
|
|
345
351
|
fmt.Fprintf(opts.stderr, "@ttsc/lint: %v\n", err)
|
package/linthost/fix.go
CHANGED
|
@@ -143,13 +143,14 @@ func runFix(opts *subcommandOpts) int {
|
|
|
143
143
|
// NoEmit forced on. Returns (nil, 2) when loading or config parsing fails.
|
|
144
144
|
func loadFixProgram(opts *subcommandOpts, needsRuleChecker bool) (*program, int) {
|
|
145
145
|
prog, parseDiags, err := loadProgram(opts.cwd, opts.tsconfig, loadProgramOptions{
|
|
146
|
-
forceNoEmit:
|
|
147
|
-
outDir:
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
146
|
+
forceNoEmit: true,
|
|
147
|
+
outDir: opts.outDir,
|
|
148
|
+
semanticConfigPath: opts.semanticConfigPath,
|
|
149
|
+
needsRuleChecker: needsRuleChecker,
|
|
150
|
+
singleThreaded: opts.singleThreaded,
|
|
151
|
+
checkers: opts.checkers,
|
|
152
|
+
tsgoArgs: opts.tsgoArgs,
|
|
153
|
+
projectIdentity: opts.projectIdentity,
|
|
153
154
|
})
|
|
154
155
|
if err != nil {
|
|
155
156
|
fmt.Fprintf(os.Stderr, "@ttsc/lint: %v\n", err)
|
package/linthost/host.go
CHANGED
|
@@ -33,6 +33,11 @@ import (
|
|
|
33
33
|
|
|
34
34
|
var programLifecycleSequence atomic.Uint64
|
|
35
35
|
|
|
36
|
+
// semanticConfigPathEnv mirrors `driver.SemanticConfigPathEnv`: the internal
|
|
37
|
+
// channel that identifies the user-authored config behind a generated wrapper.
|
|
38
|
+
// This module cannot import the ttsc driver; see the package boundary above.
|
|
39
|
+
const semanticConfigPathEnv = "TTSC_SEMANTIC_CONFIG_PATH"
|
|
40
|
+
|
|
36
41
|
// program bundles the tsgo Program with the parsed config and the standalone
|
|
37
42
|
// checker used only by type-aware lint rules.
|
|
38
43
|
type program struct {
|
|
@@ -54,9 +59,10 @@ type program struct {
|
|
|
54
59
|
}
|
|
55
60
|
|
|
56
61
|
type loadProgramOptions struct {
|
|
57
|
-
forceEmit
|
|
58
|
-
forceNoEmit
|
|
59
|
-
outDir
|
|
62
|
+
forceEmit bool
|
|
63
|
+
forceNoEmit bool
|
|
64
|
+
outDir string
|
|
65
|
+
semanticConfigPath string
|
|
60
66
|
// needsRuleChecker asks loadProgram to create the standalone checker that
|
|
61
67
|
// type-aware lint rules receive through Context.Checker.
|
|
62
68
|
needsRuleChecker bool
|
|
@@ -118,6 +124,9 @@ func loadProgram(cwd, tsconfigPath string, options loadProgramOptions) (*program
|
|
|
118
124
|
if len(parsed.Errors) > 0 {
|
|
119
125
|
return nil, parsed.Errors, nil
|
|
120
126
|
}
|
|
127
|
+
if err := applySemanticConfigPath(parsed, options.semanticConfigPath); err != nil {
|
|
128
|
+
return nil, nil, err
|
|
129
|
+
}
|
|
121
130
|
if options.forceNoEmit {
|
|
122
131
|
forceNoEmit(parsed)
|
|
123
132
|
}
|
|
@@ -158,6 +167,18 @@ func loadProgram(cwd, tsconfigPath string, options loadProgramOptions) (*program
|
|
|
158
167
|
}, nil, nil
|
|
159
168
|
}
|
|
160
169
|
|
|
170
|
+
func applySemanticConfigPath(parsed *tsoptions.ParsedCommandLine, semanticConfigPath string) error {
|
|
171
|
+
configured := strings.TrimSpace(semanticConfigPath)
|
|
172
|
+
if configured == "" {
|
|
173
|
+
return nil
|
|
174
|
+
}
|
|
175
|
+
if !filepath.IsAbs(configured) {
|
|
176
|
+
return fmt.Errorf("linthost: semantic config path must be absolute: %s", configured)
|
|
177
|
+
}
|
|
178
|
+
parsed.ParsedConfig.CompilerOptions.ConfigFilePath = shimtspath.ResolvePath(configured)
|
|
179
|
+
return nil
|
|
180
|
+
}
|
|
181
|
+
|
|
161
182
|
func normalizeProjectIdentity(
|
|
162
183
|
identity publicrule.ProjectIdentity,
|
|
163
184
|
cwd string,
|
package/linthost/lsp.go
CHANGED
|
@@ -145,10 +145,11 @@ type lspCommandOptions struct {
|
|
|
145
145
|
pluginsJSON string
|
|
146
146
|
// rangeJSON carries the editor selection used to limit quickfix.ttsc
|
|
147
147
|
// actions. Source fix-all and format actions remain document-wide.
|
|
148
|
-
rangeJSON
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
148
|
+
rangeJSON string
|
|
149
|
+
semanticConfigPath string
|
|
150
|
+
tsconfig string
|
|
151
|
+
uri string
|
|
152
|
+
projectIdentity publicrule.ProjectIdentity
|
|
152
153
|
}
|
|
153
154
|
|
|
154
155
|
// lspCommandIDs is the workspace/executeCommand ids owned by @ttsc/lint, shared
|
|
@@ -424,16 +425,17 @@ func parseLSPCommandOptions(name string, args []string) (*lspCommandOptions, boo
|
|
|
424
425
|
return nil, false
|
|
425
426
|
}
|
|
426
427
|
return &lspCommandOptions{
|
|
427
|
-
argumentsJSON:
|
|
428
|
-
command:
|
|
429
|
-
contextJSON:
|
|
430
|
-
contentStdin:
|
|
431
|
-
cwd:
|
|
432
|
-
pluginsJSON:
|
|
433
|
-
rangeJSON:
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
428
|
+
argumentsJSON: *argumentsJSON,
|
|
429
|
+
command: *command,
|
|
430
|
+
contextJSON: *contextJSON,
|
|
431
|
+
contentStdin: *contentStdin,
|
|
432
|
+
cwd: resolvedCwd,
|
|
433
|
+
pluginsJSON: *pluginsJSON,
|
|
434
|
+
rangeJSON: *rangeJSON,
|
|
435
|
+
semanticConfigPath: os.Getenv(semanticConfigPathEnv),
|
|
436
|
+
tsconfig: *tsconfig,
|
|
437
|
+
uri: *uri,
|
|
438
|
+
projectIdentity: projectIdentity,
|
|
437
439
|
}, true
|
|
438
440
|
}
|
|
439
441
|
|
|
@@ -50,7 +50,8 @@ type projectReporter struct {
|
|
|
50
50
|
mu sync.Mutex
|
|
51
51
|
active bool
|
|
52
52
|
failed bool
|
|
53
|
-
messages map[string]
|
|
53
|
+
messages map[string]publicrule.Severity
|
|
54
|
+
severity publicrule.Severity
|
|
54
55
|
state any
|
|
55
56
|
}
|
|
56
57
|
|
|
@@ -66,19 +67,27 @@ func (r *projectReporter) Fail() {
|
|
|
66
67
|
}
|
|
67
68
|
|
|
68
69
|
func (r *projectReporter) Report(message string) {
|
|
70
|
+
if r != nil {
|
|
71
|
+
r.ReportSeverity(r.severity, message)
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
func (r *projectReporter) ReportSeverity(severity publicrule.Severity, message string) {
|
|
69
76
|
if r == nil {
|
|
70
77
|
return
|
|
71
78
|
}
|
|
72
79
|
r.mu.Lock()
|
|
73
80
|
defer r.mu.Unlock()
|
|
74
|
-
if !r.active {
|
|
81
|
+
if !r.active || severity == publicrule.SeverityOff {
|
|
75
82
|
return
|
|
76
83
|
}
|
|
77
84
|
r.failed = true
|
|
78
85
|
if r.messages == nil {
|
|
79
|
-
r.messages = map[string]
|
|
86
|
+
r.messages = map[string]publicrule.Severity{}
|
|
87
|
+
}
|
|
88
|
+
if severity > r.messages[message] {
|
|
89
|
+
r.messages[message] = severity
|
|
80
90
|
}
|
|
81
|
-
r.messages[message] = struct{}{}
|
|
82
91
|
}
|
|
83
92
|
|
|
84
93
|
func (r *projectReporter) SetState(state any) {
|
|
@@ -120,7 +129,7 @@ func (r *projectReporter) snapshotLocked(close bool) publicrule.ProjectRuleResul
|
|
|
120
129
|
}
|
|
121
130
|
findings := make([]publicrule.ProjectFinding, 0, len(messages))
|
|
122
131
|
for _, message := range messages {
|
|
123
|
-
findings = append(findings, publicrule.ProjectFinding{Message: message})
|
|
132
|
+
findings = append(findings, publicrule.ProjectFinding{Message: message, Severity: r.messages[message]})
|
|
124
133
|
}
|
|
125
134
|
return publicrule.NewProjectRuleResult(status, r.state, findings, r)
|
|
126
135
|
}
|
|
@@ -144,7 +153,7 @@ func (c *projectCycle) finalize() []*Finding {
|
|
|
144
153
|
for _, finding := range result.Findings {
|
|
145
154
|
c.findings = append(c.findings, &Finding{
|
|
146
155
|
Rule: name,
|
|
147
|
-
Severity:
|
|
156
|
+
Severity: Severity(finding.Severity),
|
|
148
157
|
Message: finding.Message,
|
|
149
158
|
})
|
|
150
159
|
}
|
|
@@ -193,7 +202,7 @@ func (e *Engine) evaluateProject(
|
|
|
193
202
|
if adapter.declinesTypeChecker {
|
|
194
203
|
ruleChecker = nil
|
|
195
204
|
}
|
|
196
|
-
reporter := &projectReporter{active: true}
|
|
205
|
+
reporter := &projectReporter{active: true, severity: publicrule.Severity(setting.Severity)}
|
|
197
206
|
context := publicrule.NewProjectContext(
|
|
198
207
|
identity,
|
|
199
208
|
sources,
|
package/linthost/serve.go
CHANGED
|
@@ -80,9 +80,10 @@ func (c *residentProgramCache) acquire(
|
|
|
80
80
|
}
|
|
81
81
|
}
|
|
82
82
|
prog, diags, err := loadProgram(opts.cwd, opts.tsconfig, loadProgramOptions{
|
|
83
|
-
forceNoEmit:
|
|
84
|
-
needsRuleChecker:
|
|
85
|
-
projectIdentity:
|
|
83
|
+
forceNoEmit: true,
|
|
84
|
+
needsRuleChecker: needsChecker,
|
|
85
|
+
projectIdentity: opts.projectIdentity,
|
|
86
|
+
semanticConfigPath: opts.semanticConfigPath,
|
|
86
87
|
})
|
|
87
88
|
if err != nil {
|
|
88
89
|
return nil, nil, noopClose, err
|
|
@@ -172,9 +173,10 @@ func acquireProgram(
|
|
|
172
173
|
return residentPrograms.acquire(opts, needsChecker)
|
|
173
174
|
}
|
|
174
175
|
prog, diags, err := loadProgram(opts.cwd, opts.tsconfig, loadProgramOptions{
|
|
175
|
-
forceNoEmit:
|
|
176
|
-
needsRuleChecker:
|
|
177
|
-
projectIdentity:
|
|
176
|
+
forceNoEmit: true,
|
|
177
|
+
needsRuleChecker: needsChecker,
|
|
178
|
+
projectIdentity: opts.projectIdentity,
|
|
179
|
+
semanticConfigPath: opts.semanticConfigPath,
|
|
178
180
|
})
|
|
179
181
|
if prog == nil {
|
|
180
182
|
return prog, diags, noopClose, err
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ttsc/lint",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.29.0",
|
|
4
4
|
"description": "Reference ttsc plugin: ESLint-style lint rules over the TypeScript-Go Program used by the type-check pass.",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"@types/node": "^25.3.0",
|
|
38
38
|
"rimraf": "^6.1.2",
|
|
39
39
|
"typescript": "^7.0.2",
|
|
40
|
-
"ttsc": "0.
|
|
40
|
+
"ttsc": "0.29.0"
|
|
41
41
|
},
|
|
42
42
|
"repository": {
|
|
43
43
|
"type": "git",
|
package/rule/project.go
CHANGED
|
@@ -36,7 +36,8 @@ const (
|
|
|
36
36
|
// ProjectFinding is a non-file finding retained in a project rule's cycle
|
|
37
37
|
// result. Project findings never contain edits or source ranges.
|
|
38
38
|
type ProjectFinding struct {
|
|
39
|
-
Message
|
|
39
|
+
Message string
|
|
40
|
+
Severity Severity
|
|
40
41
|
}
|
|
41
42
|
|
|
42
43
|
// ProjectRuleResult is one snapshot of a named project rule in the current
|
|
@@ -169,6 +170,13 @@ type ProjectReporter interface {
|
|
|
169
170
|
Report(message string)
|
|
170
171
|
}
|
|
171
172
|
|
|
173
|
+
// ProjectSeverityReporter optionally accepts a severity for each finding.
|
|
174
|
+
// Reporting still marks the rule failed, including for warnings, so consumers
|
|
175
|
+
// cannot treat an incomplete project result as a clean one.
|
|
176
|
+
type ProjectSeverityReporter interface {
|
|
177
|
+
ReportSeverity(severity Severity, message string)
|
|
178
|
+
}
|
|
179
|
+
|
|
172
180
|
// ProjectContext contains the immutable inputs for one project-rule check.
|
|
173
181
|
//
|
|
174
182
|
// Sources is a defensive copy of the user sources the host read for this cycle:
|
|
@@ -256,6 +264,19 @@ func (c *ProjectContext) Report(message string) {
|
|
|
256
264
|
c.reporter.Report(message)
|
|
257
265
|
}
|
|
258
266
|
|
|
267
|
+
// ReportSeverity records a finding at an explicit level. An off rule or off
|
|
268
|
+
// finding remains silent. Hosts without this extension use the rule's level.
|
|
269
|
+
func (c *ProjectContext) ReportSeverity(severity Severity, message string) {
|
|
270
|
+
if c == nil || c.reporter == nil || c.Severity == SeverityOff || severity == SeverityOff {
|
|
271
|
+
return
|
|
272
|
+
}
|
|
273
|
+
if reporter, ok := c.reporter.(ProjectSeverityReporter); ok {
|
|
274
|
+
reporter.ReportSeverity(severity, message)
|
|
275
|
+
} else {
|
|
276
|
+
c.reporter.Report(message)
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
259
280
|
var projectRegistry []ProjectRule
|
|
260
281
|
|
|
261
282
|
// RegisterProject adds a contributor project rule to the global registry.
|