1// Copyright 2020 The Hugo Authors. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14package jsconfig
15
16import (
17	"path/filepath"
18	"sort"
19	"sync"
20)
21
22// Builder builds a jsconfig.json file that, currently, is used only to assist
23// intellinsense in editors.
24type Builder struct {
25	sourceRootsMu sync.RWMutex
26	sourceRoots   map[string]bool
27}
28
29// NewBuilder creates a new Builder.
30func NewBuilder() *Builder {
31	return &Builder{sourceRoots: make(map[string]bool)}
32}
33
34// Build builds a new Config with paths relative to dir.
35// This method is thread safe.
36func (b *Builder) Build(dir string) *Config {
37	b.sourceRootsMu.RLock()
38	defer b.sourceRootsMu.RUnlock()
39
40	if len(b.sourceRoots) == 0 {
41		return nil
42	}
43	conf := newJSConfig()
44
45	var roots []string
46	for root := range b.sourceRoots {
47		rel, err := filepath.Rel(dir, filepath.Join(root, "*"))
48		if err == nil {
49			roots = append(roots, rel)
50		}
51	}
52	sort.Strings(roots)
53	conf.CompilerOptions.Paths["*"] = roots
54
55	return conf
56}
57
58// AddSourceRoot adds a new source root.
59// This method is thread safe.
60func (b *Builder) AddSourceRoot(root string) {
61	b.sourceRootsMu.RLock()
62	found := b.sourceRoots[root]
63	b.sourceRootsMu.RUnlock()
64
65	if found {
66		return
67	}
68
69	b.sourceRootsMu.Lock()
70	b.sourceRoots[root] = true
71	b.sourceRootsMu.Unlock()
72}
73
74// CompilerOptions holds compilerOptions for jsonconfig.json.
75type CompilerOptions struct {
76	BaseURL string              `json:"baseUrl"`
77	Paths   map[string][]string `json:"paths"`
78}
79
80// Config holds the data for jsconfig.json.
81type Config struct {
82	CompilerOptions CompilerOptions `json:"compilerOptions"`
83}
84
85func newJSConfig() *Config {
86	return &Config{
87		CompilerOptions: CompilerOptions{
88			BaseURL: ".",
89			Paths:   make(map[string][]string),
90		},
91	}
92}
93