gowebbuild/vendor/github.com/evanw/esbuild/internal/cache/cache.go

102 lines
3.1 KiB
Go

package cache
import (
"sync"
"github.com/evanw/esbuild/internal/logger"
"github.com/evanw/esbuild/internal/runtime"
)
// This is a cache of the parsed contents of a set of files. The idea is to be
// able to reuse the results of parsing between builds and make subsequent
// builds faster by avoiding redundant parsing work. This only works if:
//
// * The AST information in the cache must be considered immutable. There is
// no way to enforce this in Go, but please be disciplined about this. The
// ASTs are shared in between builds. Any information that must be mutated
// in the AST during a build must be done on a shallow clone of the data if
// the mutation happens after parsing (i.e. a clone that clones everything
// that will be mutated and shares only the parts that won't be mutated).
//
// * The information in the cache must not depend at all on the contents of
// any file other than the file being cached. Invalidating an entry in the
// cache does not also invalidate any entries that depend on that file, so
// caching information that depends on other files can result in incorrect
// results due to reusing stale data. For example, do not "bake in" some
// value imported from another file.
//
// * Cached ASTs must only be reused if the parsing options are identical
// between builds. For example, it would be bad if the AST parser depended
// on options inherited from a nearby "package.json" file but those options
// were not part of the cache key. Then the cached AST could incorrectly be
// reused even if the contents of that "package.json" file have changed.
//
type CacheSet struct {
SourceIndexCache SourceIndexCache
FSCache FSCache
CSSCache CSSCache
JSONCache JSONCache
JSCache JSCache
}
func MakeCacheSet() *CacheSet {
return &CacheSet{
SourceIndexCache: SourceIndexCache{
entries: make(map[sourceIndexKey]uint32),
nextSourceIndex: runtime.SourceIndex + 1,
},
FSCache: FSCache{
entries: make(map[string]*fsEntry),
},
CSSCache: CSSCache{
entries: make(map[logger.Path]*cssCacheEntry),
},
JSONCache: JSONCache{
entries: make(map[logger.Path]*jsonCacheEntry),
},
JSCache: JSCache{
entries: make(map[logger.Path]*jsCacheEntry),
},
}
}
type SourceIndexCache struct {
mutex sync.Mutex
entries map[sourceIndexKey]uint32
nextSourceIndex uint32
}
type SourceIndexKind uint8
const (
SourceIndexNormal SourceIndexKind = iota
SourceIndexJSStubForCSS
)
type sourceIndexKey struct {
path logger.Path
kind SourceIndexKind
}
func (c *SourceIndexCache) LenHint() uint32 {
c.mutex.Lock()
defer c.mutex.Unlock()
// Add some extra room at the end for a new file or two without reallocating
const someExtraRoom = 16
return c.nextSourceIndex + someExtraRoom
}
func (c *SourceIndexCache) Get(path logger.Path, kind SourceIndexKind) uint32 {
key := sourceIndexKey{path: path, kind: kind}
c.mutex.Lock()
defer c.mutex.Unlock()
if sourceIndex, ok := c.entries[key]; ok {
return sourceIndex
}
sourceIndex := c.nextSourceIndex
c.nextSourceIndex++
c.entries[key] = sourceIndex
return sourceIndex
}