Skip to content

Commit efb6219

Browse files
committed
tuning vacuum experience
Signed-off-by: quobix <dave@quobix.com>
1 parent c604716 commit efb6219

File tree

10 files changed

+98
-31
lines changed

10 files changed

+98
-31
lines changed

cmd/lint.go

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,7 @@ func lintFile(req lintFileRequest) error {
254254
result := motor.ApplyRulesToRuleSet(&motor.RuleSetExecution{
255255
RuleSet: req.selectedRS,
256256
Spec: specBytes,
257+
SpecFileName: req.fileName,
257258
CustomFunctions: req.functions,
258259
Base: req.baseFlag,
259260
AllowLookup: true,
@@ -311,11 +312,15 @@ func processResults(results []*model.RuleFunctionResult, specData []string, snip
311312
if !snippets {
312313
tableData = [][]string{{"Location", "Severity", "Message", "Rule", "Category", "Path"}}
313314
}
315+
316+
// width, height, err := terminal.GetSize(0)
317+
// TODO: determine the terminal size and render the linting results in a table that fits the screen.
318+
314319
for i, r := range results {
315320

316-
if i > 200 {
321+
if i > 1000 {
317322
tableData = append(tableData, []string{"", "", pterm.LightRed(fmt.Sprintf("...%d "+
318-
"more violations not rendered.", len(results)-200)), ""})
323+
"more violations not rendered.", len(results)-1000)), ""})
319324
break
320325
}
321326
if snippets {
@@ -330,9 +335,16 @@ func processResults(results []*model.RuleFunctionResult, specData []string, snip
330335
startCol = r.StartNode.Column
331336
}
332337

333-
start := fmt.Sprintf("%s:%v:%v", filename, startLine, startCol)
338+
f := filename
339+
if r.Origin != nil {
340+
f = r.Origin.AbsoluteLocation
341+
startLine = r.Origin.Line
342+
startCol = r.Origin.Column
343+
}
344+
start := fmt.Sprintf("%s:%v:%v", f, startLine, startCol)
334345
m := r.Message
335346
p := r.Path
347+
336348
if len(r.Path) > 60 {
337349
p = fmt.Sprintf("%s...", r.Path[:60])
338350
}

functions/openapi/unused_component.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,15 @@ func (uc UnusedComponent) RunRule(nodes []*yaml.Node, context model.RuleFunction
104104
for key, ref := range resultMap {
105105

106106
// check everything!
107-
if allRefs[key] == nil {
107+
u := strings.Split(key, "#/")
108+
var keyAlt = key
109+
if len(u) == 2 {
110+
if u[0] == "" {
111+
keyAlt = fmt.Sprintf("%s#/%s", context.Index.GetSpecAbsolutePath(), u[1])
112+
}
113+
}
114+
115+
if allRefs[key] == nil && allRefs[keyAlt] == nil {
108116
found := false
109117
// check poly refs if the reference can't be found
110118
if oneOfRefs[key] != nil || allOfRefs[key] != nil || anyOfRefs[key] != nil {
@@ -128,11 +136,11 @@ func (uc UnusedComponent) RunRule(nodes []*yaml.Node, context model.RuleFunction
128136
_, path := utils.ConvertComponentIdIntoPath(ref.Definition)
129137

130138
// roll back node by one, so we have the actual start.
131-
rolledBack := *ref.Node
132-
rolledBack.Line = ref.Node.Line - 1
139+
//rolledBack := *ref.Node
140+
//rolledBack.Line = ref.Node.Line - 1
133141
results = append(results, model.RuleFunctionResult{
134142
Message: fmt.Sprintf("`%s` is potentially unused or has been orphaned", key),
135-
StartNode: &rolledBack,
143+
StartNode: ref.Node,
136144
EndNode: utils.FindLastChildNodeWithLevel(ref.Node, 0),
137145
Path: path,
138146
Rule: context.Rule,

go.mod

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ require (
2020
github.com/spf13/viper v1.17.0
2121
github.com/stretchr/testify v1.8.4
2222
github.com/vmware-labs/yaml-jsonpath v0.3.2
23+
golang.org/x/crypto v0.15.0
2324
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa
2425
gopkg.in/yaml.v3 v3.0.1
2526
)
@@ -58,8 +59,8 @@ require (
5859
go.uber.org/multierr v1.11.0 // indirect
5960
golang.org/x/sync v0.3.0 // indirect
6061
golang.org/x/sys v0.14.0 // indirect
61-
golang.org/x/term v0.13.0 // indirect
62-
golang.org/x/text v0.13.0 // indirect
62+
golang.org/x/term v0.14.0 // indirect
63+
golang.org/x/text v0.14.0 // indirect
6364
gopkg.in/ini.v1 v1.67.0 // indirect
6465
gopkg.in/yaml.v2 v2.4.0 // indirect
6566
)

go.sum

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
338338
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
339339
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
340340
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
341+
golang.org/x/crypto v0.15.0 h1:frVn1TEaCEaZcn3Tmd7Y2b5KKPaZ+I32Q2OA3kYp5TA=
342+
golang.org/x/crypto v0.15.0/go.mod h1:4ChreQoLWfG3xLDer1WdlH5NdlQ3+mwnQq1YTKY+72g=
341343
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
342344
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
343345
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -495,8 +497,8 @@ golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9sn
495497
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
496498
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
497499
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
498-
golang.org/x/term v0.13.0 h1:bb+I9cTfFazGW51MZqBVmZy7+JEJMouUHTUSKVQLBek=
499-
golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U=
500+
golang.org/x/term v0.14.0 h1:LGK9IlZ8T9jvdy6cTdfKUCltatMFOehAQo9SRC46UQ8=
501+
golang.org/x/term v0.14.0/go.mod h1:TySc+nGkYR6qt8km8wUhuFRTVSMIX3XPR58y2lC8vww=
500502
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
501503
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
502504
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -508,8 +510,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
508510
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
509511
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
510512
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
511-
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
512-
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
513+
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
514+
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
513515
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
514516
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
515517
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=

model/rules.go

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -50,15 +50,16 @@ type RuleFunctionContext struct {
5050

5151
// RuleFunctionResult describes a failure with linting after being run through a rule
5252
type RuleFunctionResult struct {
53-
Message string `json:"message" yaml:"message"` // What failed and why?
54-
Range reports.Range `json:"range" yaml:"range"` // Where did it happen?
55-
Path string `json:"path" yaml:"path"` // the JSONPath to where it can be found
56-
RuleId string `json:"ruleId" yaml:"ruleId"` // The ID of the rule
57-
RuleSeverity string `json:"ruleSeverity" yaml:"ruleSeverity"` // the severity of the rule used
58-
Rule *Rule `json:"-" yaml:"-"` // The rule used
59-
StartNode *yaml.Node `json:"-" yaml:"-"` // Start of the violation
60-
EndNode *yaml.Node `json:"-" yaml:"-"` // end of the violation
61-
Timestamp *time.Time `json:"-" yaml:"-"` // When the result was created.
53+
Message string `json:"message" yaml:"message"` // What failed and why?
54+
Range reports.Range `json:"range" yaml:"range"` // Where did it happen?
55+
Path string `json:"path" yaml:"path"` // the JSONPath to where it can be found
56+
RuleId string `json:"ruleId" yaml:"ruleId"` // The ID of the rule
57+
RuleSeverity string `json:"ruleSeverity" yaml:"ruleSeverity"` // the severity of the rule used
58+
Origin *index.NodeOrigin `json:"origin,omitempty" yaml:"origin,omitempty"` // Where did the result come from?
59+
Rule *Rule `json:"-" yaml:"-"` // The rule used
60+
StartNode *yaml.Node `json:"-" yaml:"-"` // Start of the violation
61+
EndNode *yaml.Node `json:"-" yaml:"-"` // end of the violation
62+
Timestamp *time.Time `json:"-" yaml:"-"` // When the result was created.
6263

6364
// ModelContext may or may nor be populated, depending on the rule used and the context of the rule. If it is
6465
// populated, then this is a reference to the model that fired the rule. (not currently used yet)

model/test_files/mixedref-burgershop.openapi.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ paths:
166166
schema:
167167
type: array
168168
items:
169-
$ref: 'test_files/burgershop.openapi.yaml#/components/schemas/Dressing'
169+
$ref: "./burgershop.openapi.yaml#/components/schemas/Dressing"
170170
"404":
171171
description: Cannot find your burger in which to list dressings. Sorry
172172
content:
@@ -222,7 +222,7 @@ paths:
222222
schema:
223223
type: array
224224
items:
225-
$ref: 'test_files/burgershop.openapi.yaml#/components/schemas/Dressing'
225+
$ref: "./burgershop.openapi.yaml#/components/schemas/Dressing"
226226
"500":
227227
description: Unexpected error. Sorry.
228228
content:

motor/build_rolodex.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,12 @@ func BuildRolodexFromIndexConfig(indexConfig *index.SpecIndexConfig) (*index.Rol
2222
}
2323

2424
// create a local filesystem
25-
fileFS, err := index.NewLocalFS(cwd, os.DirFS(cwd))
25+
fsCfg := &index.LocalFSConfig{
26+
BaseDirectory: cwd,
27+
IndexConfig: indexConfig,
28+
DirFS: os.DirFS(cwd),
29+
}
30+
fileFS, err := index.NewLocalFSWithConfig(fsCfg)
2631
if err != nil {
2732
return nil, err
2833
}

motor/rule_applicator.go

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"fmt"
99
"log/slog"
1010
"net/url"
11+
"path/filepath"
1112
"sync"
1213

1314
"github.com/daveshanley/vacuum/functions"
@@ -43,6 +44,7 @@ type ruleContext struct {
4344
// of ApplyRulesToRuleSet to change, without a huge refactor. The ApplyRulesToRuleSet function only returns a single error also.
4445
type RuleSetExecution struct {
4546
RuleSet *rulesets.RuleSet // The RuleSet in which to apply
47+
SpecFileName string // The name of the specification file, used to correctly label location
4648
Spec []byte // The raw bytes of the OpenAPI specification.
4749
SpecInfo *datamodel.SpecInfo // Pre-parsed spec-info.
4850
CustomFunctions map[string]model.RuleFunction // custom functions loaded from plugin.
@@ -392,7 +394,7 @@ func ApplyRulesToRuleSet(execution *RuleSetExecution) *RuleSetExecutionResult {
392394
ruleWaitGroup.Wait()
393395
}
394396

395-
ruleResults = *removeDuplicates(&ruleResults)
397+
ruleResults = *removeDuplicates(&ruleResults, execution, indexResolved)
396398

397399
return &RuleSetExecutionResult{
398400
RuleSetExecution: execution,
@@ -552,7 +554,7 @@ type seenResult struct {
552554
message string
553555
}
554556

555-
func removeDuplicates(results *[]model.RuleFunctionResult) *[]model.RuleFunctionResult {
557+
func removeDuplicates(results *[]model.RuleFunctionResult, rse *RuleSetExecution, idx *index.SpecIndex) *[]model.RuleFunctionResult {
556558
seen := make(map[string][]*seenResult)
557559
var newResults []model.RuleFunctionResult
558560
for _, result := range *results {
@@ -567,6 +569,13 @@ func removeDuplicates(results *[]model.RuleFunctionResult) *[]model.RuleFunction
567569
result.Message,
568570
},
569571
}
572+
origin := idx.FindNodeOrigin(result.StartNode)
573+
if origin != nil {
574+
if filepath.Base(origin.AbsoluteLocation) == "root.yaml" {
575+
origin.AbsoluteLocation = rse.SpecFileName
576+
}
577+
result.Origin = origin
578+
}
570579
newResults = append(newResults, result)
571580
}
572581
} else {
@@ -583,6 +592,13 @@ func removeDuplicates(results *[]model.RuleFunctionResult) *[]model.RuleFunction
583592
result.Message,
584593
},
585594
}
595+
origin := idx.FindNodeOrigin(result.StartNode)
596+
if origin != nil {
597+
if filepath.Base(origin.AbsoluteLocation) == "root.yaml" {
598+
origin.AbsoluteLocation = rse.SpecFileName
599+
}
600+
result.Origin = origin
601+
}
586602
newResults = append(newResults, result)
587603
}
588604
}

parser/json_schema.go

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"github.com/pb33f/libopenapi/index"
1919
"github.com/pb33f/libopenapi/utils"
2020
"gopkg.in/yaml.v3"
21+
"strings"
2122
"time"
2223
)
2324

@@ -142,13 +143,34 @@ func ConvertYAMLIntoJSONSchema(str string, index *index.SpecIndex) (*highBase.Sc
142143
return ConvertNodeIntoJSONSchema(node.Content[0], index)
143144
}
144145

145-
func ConvertNodeIntoJSONSchema(node *yaml.Node, index *index.SpecIndex) (*highBase.Schema, error) {
146+
func ConvertNodeIntoJSONSchema(node *yaml.Node, idx *index.SpecIndex) (*highBase.Schema, error) {
146147
sch := lowBase.Schema{}
147148
mbErr := low.BuildModel(node, &sch)
148149
if mbErr != nil {
149150
return nil, mbErr
150151
}
151-
schErr := sch.Build(context.Background(), node, index)
152+
153+
var path = ""
154+
155+
isRef, _, ref := utils.IsNodeRefValue(node)
156+
if isRef {
157+
r := strings.Split(ref, "#")
158+
if len(r) == 2 {
159+
if r[0] != "" {
160+
path = r[0]
161+
}
162+
} else {
163+
path = r[0]
164+
}
165+
}
166+
167+
if path == "" && idx != nil {
168+
path = idx.GetSpecAbsolutePath()
169+
}
170+
171+
ctx := context.WithValue(context.Background(), index.CurrentPathKey, path)
172+
173+
schErr := sch.Build(ctx, node, idx)
152174
if schErr != nil {
153175
return nil, schErr
154176
}

rulesets/rulesets.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -365,14 +365,14 @@ func GetAllBuiltInRules() map[string]*model.Rule {
365365
rules[Oas2OperationFormDataConsumeCheck] = GetOAS2FormDataConsumesRule()
366366
rules[Oas2AnyOf] = GetOAS2PolymorphicAnyOfRule()
367367
rules[Oas2OneOf] = GetOAS2PolymorphicOneOfRule()
368-
rules[Oas3ValidSchemaExample] = GetOAS3ExamplesRule()
369-
rules[Oas2ValidSchemaExample] = GetOAS2ExamplesRule()
370368
rules[NoAmbiguousPathsRule] = NoAmbiguousPaths()
371369
rules[NoVerbsInPath] = GetNoVerbsInPathRule()
372370
rules[PathsKebabCase] = GetPathsKebabCaseRule()
373371
rules[OperationErrorResponse] = GetOperationErrorResponseRule()
374372
rules[Oas2Schema] = GetOAS2SchemaRule()
375373
rules[Oas3Schema] = GetOAS3SchemaRule()
374+
rules[Oas3ValidSchemaExample] = GetOAS3ExamplesRule()
375+
rules[Oas2ValidSchemaExample] = GetOAS2ExamplesRule()
376376

377377
return rules
378378
}

0 commit comments

Comments
 (0)