44 "errors"
55 "fmt"
66 "io/fs"
7+ "os"
78 "path/filepath"
89 "strings"
910
@@ -13,6 +14,10 @@ import (
1314 "github.com/errata-ai/vale/v3/internal/system"
1415)
1516
17+ var pathKeys = []string {
18+ "StylesPath" ,
19+ }
20+
1621var coreError = "'%s' is a core option; it should be defined above any syntax-specific options (`[...]`)."
1722
1823func mergeValues (shadows []string ) []string {
@@ -161,40 +166,15 @@ var globalOpts = map[string]func(*ini.Section, *Config){
161166
162167var coreOpts = map [string ]func (* ini.Section , * Config ) error {
163168 "StylesPath" : func (sec * ini.Section , cfg * Config ) error {
164- // NOTE: The order of these paths is important. They represent the load
165- // order of the configuration files -- not `cfg.Paths`.
166169 paths := sec .Key ("StylesPath" ).ValueWithShadows ()
167- files := cfg .ConfigFiles
168- if cfg .Flags .Local && len (files ) == 2 {
169- // This represents the case where we have a default `.vale.ini`
170- // file and a local `.vale.ini` file.
171- //
172- // In such a case, there are three options: (1) both files define a
173- // `StylesPath`, (2) only one file defines a `StylesPath`, or (3)
174- // neither file defines a `StylesPath`.
175- basePath := system .DeterminePath (files [0 ], filepath .FromSlash (paths [0 ]))
176- mockPath := system .DeterminePath (files [1 ], filepath .FromSlash (paths [0 ]))
177- // ^ This case handles the situation where both configs define the
178- // same StylesPath (e.g., `StylesPath = styles`).
179- if len (paths ) == 2 {
180- basePath = system .DeterminePath (files [0 ], filepath .FromSlash (paths [0 ]))
181- mockPath = system .DeterminePath (files [1 ], filepath .FromSlash (paths [1 ]))
182- }
183- cfg .AddStylesPath (basePath )
184- cfg .AddStylesPath (mockPath )
185- } else if len (paths ) > 0 {
186- // In this case, we have a local configuration file (no default)
187- // that defines a `StylesPath`.
188- candidate := filepath .FromSlash (paths [len (paths )- 1 ])
189- path := system .DeterminePath (cfg .ConfigFile (), candidate )
190-
191- cfg .AddStylesPath (path )
170+ for _ , path := range paths {
192171 if ! system .FileExists (path ) {
193172 return NewE201FromTarget (
194173 fmt .Sprintf ("The path '%s' does not exist." , path ),
195- candidate ,
174+ path ,
196175 cfg .Flags .Path )
197176 }
177+ cfg .AddStylesPath (path )
198178 }
199179 return nil
200180 },
@@ -255,10 +235,78 @@ var coreOpts = map[string]func(*ini.Section, *Config) error{
255235 },
256236}
257237
238+ func expandPaths (file * ini.File , source interface {}) {
239+ var path string
240+
241+ switch s := source .(type ) {
242+ case string :
243+ abs , _ := filepath .Abs (s )
244+ path = filepath .Dir (abs )
245+ default :
246+ path , _ = os .Getwd ()
247+ }
248+
249+ for _ , section := range file .Sections () {
250+ for _ , key := range section .Keys () {
251+ if StringInSlice (key .Name (), pathKeys ) {
252+ value := key .Value ()
253+ if ! filepath .IsAbs (value ) {
254+ key .SetValue (filepath .Join (path , value ))
255+ }
256+ }
257+ }
258+ }
259+ }
260+
261+ func shadowMerge (primary * ini.File , secondary * ini.File ) {
262+ for _ , secondarySection := range secondary .Sections () {
263+ sectionName := secondarySection .Name ()
264+
265+ primarySection , _ := primary .GetSection (sectionName )
266+ if primarySection == nil {
267+ primarySection , _ = primary .NewSection (sectionName )
268+ }
269+
270+ for _ , secondaryKey := range secondarySection .Keys () {
271+ keyName := secondaryKey .Name ()
272+ keyValue := secondaryKey .Value ()
273+
274+ primaryKey , _ := primarySection .GetKey (keyName )
275+ if primaryKey == nil {
276+ primarySection .NewKey (keyName , keyValue )
277+ } else {
278+ primaryKey .AddShadow (keyValue )
279+ }
280+ }
281+ }
282+ }
283+
258284func shadowLoad (source interface {}, others ... interface {}) (* ini.File , error ) {
259- return ini . LoadSources ( ini.LoadOptions {
285+ options := ini.LoadOptions {
260286 AllowShadows : true ,
261- SpaceBeforeInlineComment : true }, source , others ... )
287+ Loose : true ,
288+ SpaceBeforeInlineComment : true ,
289+ }
290+
291+ primary , err := ini .LoadSources (options , source )
292+ if err != nil {
293+ return nil , err
294+ }
295+ expandPaths (primary , source )
296+
297+ for _ , other := range others {
298+ var shadow * ini.File
299+
300+ shadow , err = ini .LoadSources (options , other )
301+ if err != nil {
302+ return nil , err
303+ }
304+
305+ expandPaths (shadow , other )
306+ shadowMerge (primary , shadow )
307+ }
308+
309+ return primary , nil
262310}
263311
264312func processSources (cfg * Config , sources []string ) (* ini.File , error ) {
0 commit comments