Skip to content

Commit 772c4f6

Browse files
committed
feat: add support for JSON, YAML, and TOML
1 parent 0bac7ed commit 772c4f6

File tree

24 files changed

+504
-36
lines changed

24 files changed

+504
-36
lines changed

go.mod

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,17 @@ require (
2020
github.com/niklasfasching/go-org v1.6.6
2121
github.com/olekukonko/tablewriter v0.0.4
2222
github.com/otiai10/copy v1.7.0
23+
github.com/pelletier/go-toml/v2 v2.2.3
2324
github.com/pterm/pterm v0.12.76
2425
github.com/remeh/sizedwaitgroup v1.0.0
2526
github.com/smacker/go-tree-sitter v0.0.0-20240514083259-c5d1f3f5f99e
2627
github.com/spf13/pflag v1.0.5
27-
github.com/stretchr/testify v1.8.4
28+
github.com/stretchr/testify v1.9.0
29+
github.com/tomwright/dasel/v2 v2.8.1
2830
github.com/yuin/goldmark v1.5.6
2931
golang.org/x/exp v0.0.0-20231006140011-7918f672742d
30-
golang.org/x/net v0.23.0
31-
golang.org/x/sys v0.18.0
32+
golang.org/x/net v0.25.0
33+
golang.org/x/sys v0.20.0
3234
gopkg.in/yaml.v2 v2.4.0
3335
)
3436

@@ -64,9 +66,9 @@ require (
6466
github.com/ulikunitz/xz v0.5.10 // indirect
6567
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
6668
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
67-
golang.org/x/crypto v0.21.0 // indirect
68-
golang.org/x/term v0.18.0 // indirect
69-
golang.org/x/text v0.14.0 // indirect
69+
golang.org/x/crypto v0.23.0 // indirect
70+
golang.org/x/term v0.20.0 // indirect
71+
golang.org/x/text v0.15.0 // indirect
7072
gopkg.in/neurosnap/sentences.v1 v1.0.7 // indirect
7173
gopkg.in/yaml.v3 v3.0.1 // indirect
7274
)

go.sum

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6
119119
github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo=
120120
github.com/otiai10/mint v1.3.3 h1:7JgpsBaN0uMkyju4tbYHu0mnM55hNKVYLsXmwr15NQI=
121121
github.com/otiai10/mint v1.3.3/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc=
122+
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
123+
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
122124
github.com/pierrec/lz4/v4 v4.1.2 h1:qvY3YFXRQE/XB8MlLzJH7mSzBs74eA2gg52YTk6jUPM=
123125
github.com/pierrec/lz4/v4 v4.1.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
124126
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@@ -159,8 +161,10 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
159161
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
160162
github.com/stretchr/testify v1.7.4/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
161163
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
162-
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
163-
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
164+
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
165+
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
166+
github.com/tomwright/dasel/v2 v2.8.1 h1:mo5SlL0V2d3a0uPsD9Rrndn0cHWpbNDheB4+Fm++z8k=
167+
github.com/tomwright/dasel/v2 v2.8.1/go.mod h1:6bNDNAnmGEtGpuIvksuQwiNcAgQ87pmzndynsqTNglc=
164168
github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
165169
github.com/ulikunitz/xz v0.5.9/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
166170
github.com/ulikunitz/xz v0.5.10 h1:t92gobL9l3HE202wg3rlk19F6X+JOxl9BBrCCMYEYd8=
@@ -176,8 +180,8 @@ github.com/yuin/goldmark v1.5.6/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5ta
176180
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
177181
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
178182
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
179-
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
180-
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
183+
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
184+
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
181185
golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
182186
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
183187
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
@@ -187,8 +191,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
187191
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
188192
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
189193
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
190-
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
191-
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
194+
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
195+
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
192196
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
193197
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
194198
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -204,24 +208,24 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
204208
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
205209
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
206210
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
207-
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
208-
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
211+
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
212+
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
209213
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
210214
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
211215
golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
212216
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
213217
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
214218
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
215-
golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=
216-
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
219+
golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw=
220+
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
217221
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
218222
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
219223
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
220224
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
221225
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
222226
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
223-
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
224-
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
227+
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
228+
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
225229
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
226230
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
227231
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=

internal/core/blueprint.go

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
package core
2+
3+
import (
4+
"encoding/json"
5+
"errors"
6+
"fmt"
7+
"os"
8+
9+
"github.com/pelletier/go-toml/v2"
10+
"github.com/tomwright/dasel/v2"
11+
"gopkg.in/yaml.v2"
12+
)
13+
14+
type DaselValue = map[string]any
15+
16+
var blueprintEngines = []string{"tree-sitter", "dasel", "command"}
17+
18+
// A Query is a single query that we want to run against a document.
19+
//
20+
// The result of the query is optionally assigned the given scope.
21+
type Query struct {
22+
Scope string `yaml:"scope"`
23+
Operation string `yaml:"operation"`
24+
}
25+
26+
// A Blueprint is a set of queries that we want to run against a document.
27+
//
28+
// The supported engines are:
29+
//
30+
// - `tree-sitter`
31+
// - `dasel`
32+
// - `command`
33+
type Blueprint struct {
34+
Engine string `yaml:"engine"`
35+
Steps []Query `yaml:"steps"`
36+
}
37+
38+
// A ScopedValues is a value that has been assigned a scope.
39+
type ScopedValues struct {
40+
Scope string
41+
Values []string
42+
}
43+
44+
// NewBlueprint creates a new blueprint from the given path.
45+
func NewBlueprint(path string) (*Blueprint, error) {
46+
var blueprint Blueprint
47+
48+
data, err := os.ReadFile(path)
49+
if err != nil {
50+
return nil, err
51+
}
52+
53+
err = yaml.Unmarshal(data, &blueprint)
54+
if err != nil {
55+
return nil, err
56+
}
57+
58+
if blueprint.Engine == "" {
59+
return nil, fmt.Errorf("missing parser")
60+
} else if !StringInSlice(blueprint.Engine, blueprintEngines) {
61+
return nil, fmt.Errorf("unsupported parser: %s", blueprint.Engine)
62+
}
63+
64+
if len(blueprint.Steps) == 0 {
65+
return nil, fmt.Errorf("missing queries")
66+
}
67+
68+
return &blueprint, nil
69+
}
70+
71+
func (b *Blueprint) Apply(f *File) ([]ScopedValues, error) {
72+
found := []ScopedValues{}
73+
74+
value, err := fileToValue(f)
75+
if err != nil {
76+
return nil, NewE100(f.Path, err)
77+
}
78+
79+
for _, s := range b.Steps {
80+
selected, err := dasel.Select(value, s.Operation)
81+
if err != nil {
82+
return found, err
83+
}
84+
85+
values := []string{}
86+
for _, v := range selected {
87+
values = append(values, v.String())
88+
}
89+
90+
found = append(found, ScopedValues{
91+
Scope: s.Scope,
92+
Values: values,
93+
})
94+
}
95+
96+
return found, nil
97+
}
98+
99+
func fileToValue(f *File) (DaselValue, error) {
100+
var value DaselValue
101+
102+
contents := []byte(f.Content)
103+
switch f.RealExt {
104+
case ".json":
105+
err := json.Unmarshal(contents, &value)
106+
if err != nil {
107+
return nil, err
108+
}
109+
case ".yml":
110+
err := yaml.Unmarshal(contents, &value)
111+
if err != nil {
112+
return nil, err
113+
}
114+
case ".toml":
115+
err := toml.Unmarshal(contents, &value)
116+
if err != nil {
117+
return nil, err
118+
}
119+
default:
120+
return nil, errors.New("unsupported file type")
121+
}
122+
123+
return value, nil
124+
}

internal/core/config.go

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,14 @@ var (
3333
// PipeDir is the default location for Vale's configuration pipeline.
3434
PipeDir = ".vale-config"
3535

36-
VocabDir = filepath.Join(ConfigDir, "vocabularies")
37-
DictDir = filepath.Join(ConfigDir, "dictionaries")
38-
TmplDir = filepath.Join(ConfigDir, "templates")
39-
IgnoreDir = filepath.Join(ConfigDir, "ignore")
40-
ActionDir = filepath.Join(ConfigDir, "actions")
41-
FilterDir = filepath.Join(ConfigDir, "filters")
42-
ScriptDir = filepath.Join(ConfigDir, "scripts")
36+
VocabDir = filepath.Join(ConfigDir, "vocabularies")
37+
DictDir = filepath.Join(ConfigDir, "dictionaries")
38+
TmplDir = filepath.Join(ConfigDir, "templates")
39+
IgnoreDir = filepath.Join(ConfigDir, "ignore")
40+
ActionDir = filepath.Join(ConfigDir, "actions")
41+
FilterDir = filepath.Join(ConfigDir, "filters")
42+
ScriptDir = filepath.Join(ConfigDir, "scripts")
43+
BlueprintsDir = filepath.Join(ConfigDir, "blueprints")
4344
)
4445

4546
// ConfigDirs is a list of all directories that contain user-defined, non-style
@@ -52,6 +53,7 @@ var ConfigDirs = []string{
5253
ActionDir,
5354
ScriptDir,
5455
FilterDir,
56+
BlueprintsDir,
5557
}
5658

5759
// ConfigVars is a list of all supported environment variables.
@@ -210,9 +212,10 @@ type Config struct {
210212
AcceptedTokens []string `json:"-"` // Project-specific vocabulary (okay)
211213
RejectedTokens []string `json:"-"` // Project-specific vocabulary (avoid)
212214

213-
FallbackPath string `json:"-"`
214-
SecToPat map[string]glob.Glob `json:"-"`
215-
Styles []string `json:"-"`
215+
FallbackPath string `json:"-"`
216+
SecToPat map[string]glob.Glob `json:"-"`
217+
Styles []string `json:"-"`
218+
Blueprints map[string]*Blueprint `json:"-"`
216219

217220
NLPEndpoint string // An external API to call for NLP-related work.
218221

@@ -241,6 +244,7 @@ func NewConfig(flags *CLIFlags) (*Config, error) {
241244
cfg.TokenIgnores = make(map[string][]string)
242245
cfg.CommentDelimiters = make(map[string][2]string)
243246
cfg.FormatToLang = make(map[string]string)
247+
cfg.Blueprints = make(map[string]*Blueprint)
244248
cfg.Paths = []string{}
245249
cfg.ConfigFiles = []string{}
246250

internal/core/file.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,10 +92,11 @@ func NewFile(src string, config *Config) (*File, error) {
9292
baseStyles := config.GBaseStyles
9393
checks := make(map[string]bool)
9494

95+
names := []string{}
9596
for _, fp := range filepaths {
9697
for _, sec := range config.StyleKeys {
9798
if pat, found := config.SecToPat[sec]; found && pat.Match(fp) {
98-
baseStyles = config.SBaseStyles[sec]
99+
names = append(names, config.SBaseStyles[sec]...)
99100
}
100101
}
101102

@@ -108,6 +109,10 @@ func NewFile(src string, config *Config) (*File, error) {
108109
}
109110
}
110111

112+
if len(names) > 0 {
113+
baseStyles = UniqueStrings(names)
114+
}
115+
111116
lang := "en"
112117
for syntax, code := range config.FormatToLang {
113118
sec, err := glob.Compile(syntax)

internal/core/format.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,9 @@ var FormatByExtension = map[string][]string{
8888
`\.(?:ts|tsx)$`: {".ts", "code"},
8989
`\.(?:txt)$`: {".txt", "text"},
9090
`\.(?:xml)$`: {".xml", "markup"},
91-
`\.(?:yaml|yml)$`: {".yml", "code"},
91+
`\.(?:yaml|yml)$`: {".yml", "data"},
92+
`\.(?:json)$`: {".json", "data"},
93+
`\.(?:toml)$`: {".toml", "data"},
9294
}
9395

9496
// FormatFromExt takes a file extension and returns its [normExt, format]
@@ -101,6 +103,12 @@ func FormatFromExt(path string, mapping map[string]string) (string, string) {
101103
if kind == "code" && getFormat("."+format) == "markup" {
102104
// NOTE: This is a special case of embedded markup within code.
103105
return "." + format, "fragment"
106+
} else if kind == "data" && getFormat("."+format) == "markup" {
107+
// NOTE: This is a special case of embedded markup within data.
108+
//
109+
// Unlike code, data formats are *always* linted as a fragment with
110+
// the default format as plain text.
111+
return "." + format, "data"
104112
}
105113
base = format
106114
}

internal/core/ini.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,22 @@ var syntaxOpts = map[string]func(string, *ini.Section, *Config) error{
138138
cfg.FormatToLang[label] = sec.Key("Lang").String()
139139
return nil
140140
},
141+
"Blueprint": func(label string, sec *ini.Section, cfg *Config) error { //nolint:unparam
142+
name := sec.Key("Blueprint").String()
143+
144+
path := FindConfigAsset(cfg, name+".yml", BlueprintsDir)
145+
if path == "" {
146+
return fmt.Errorf("blueprint '%s' not found", name)
147+
}
148+
149+
blueprint, err := NewBlueprint(path)
150+
if err != nil {
151+
return err
152+
}
153+
154+
cfg.Blueprints[label] = blueprint
155+
return nil
156+
},
141157
}
142158

143159
var globalOpts = map[string]func(*ini.Section, *Config){

internal/core/util.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,3 +349,18 @@ func FindProcess(pid int) *os.Process {
349349

350350
return p
351351
}
352+
353+
// UniqueStrings returns a new slice with all duplicate strings removed.
354+
func UniqueStrings(slice []string) []string {
355+
keys := make(map[string]bool)
356+
list := []string{}
357+
358+
for _, entry := range slice {
359+
if _, value := keys[entry]; !value {
360+
keys[entry] = true
361+
list = append(list, entry)
362+
}
363+
}
364+
365+
return list
366+
}

internal/lint/ast.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,14 +150,14 @@ func (l *Linter) lintScope(f *core.File, state *walker, txt string) error {
150150
f.Metrics[strings.TrimPrefix(scope, "text.")]++
151151

152152
txt = strings.TrimLeft(txt, " ")
153-
b := state.block(txt, scope+f.RealExt)
153+
b := state.block(txt, scope+l.metaScope+f.RealExt)
154154
return l.lintBlock(f, b, state.lines, 0, false)
155155
}
156156
}
157157

158158
f.Summary.WriteString(txt + "\n\n")
159159

160-
b := state.block(txt, "txt")
160+
b := state.block(txt, "text"+l.metaScope+f.RealExt)
161161
return l.lintProse(f, b, state.lines)
162162
}
163163

0 commit comments

Comments
 (0)