blob: a4c3488bf79a86fb2433dfd256e462dc1237e664 [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package javascript
import (
"sort"
"strconv"
"v.io/v23/vdl"
"v.io/x/lib/set"
"v.io/x/ref/lib/vdl/compile"
)
// TODO(bjornick): Merge with pkg_types.go
// jsImport represents a single package import.
type jsImport struct {
Path string // Path of the imported package; e.g. "v.io/x/ref/lib/vdl/testdata/arith"
// Local name that refers to the imported package; either the non-empty import
// name, or the name of the imported package.
Local string
}
// jsImports is a collection of package imports.
// REQUIRED: The imports must be sorted by path.
type jsImports []jsImport
// LookupLocal returns the local name that identifies the given pkgPath.
func (x jsImports) LookupLocal(pkgPath string) string {
ix := sort.Search(len(x), func(i int) bool { return x[i].Path >= pkgPath })
if ix < len(x) && x[ix].Path == pkgPath {
return x[ix].Local
}
return ""
}
// Each import must end up with a unique local name - when we see a collision we
// simply add a "_N" suffix where N starts at 2 and increments.
func uniqueImport(pkgName, pkgPath string, seen map[string]bool) jsImport {
iter := 1
for {
local := pkgName
if iter > 1 {
local += "_" + strconv.Itoa(iter)
}
if !seen[local] {
// Found a unique local name - return the import.
seen[local] = true
return jsImport{pkgPath, local}
}
iter++
}
}
type pkgSorter []*compile.Package
func (s pkgSorter) Len() int { return len(s) }
func (s pkgSorter) Less(i, j int) bool { return s[i].Path < s[j].Path }
func (s pkgSorter) Swap(i, j int) { s[j], s[i] = s[i], s[j] }
// jsImportsForFiles returns the imports required for the given files.
func jsImportsForFiles(files ...*compile.File) jsImports {
seenPath := make(map[string]bool)
pkgs := pkgSorter{}
for _, f := range files {
// TODO(toddw,bjornick): Remove File.PackageDeps and replace by walking through each type.
for _, dep := range f.PackageDeps {
if seenPath[dep.Path] {
continue
}
seenPath[dep.Path] = true
pkgs = append(pkgs, dep)
}
}
sort.Sort(pkgs)
var ret jsImports
seenName := make(map[string]bool)
for _, dep := range pkgs {
ret = append(ret, uniqueImport(dep.Name, dep.GenPath, seenName))
}
return ret
}
// pkgDeps maintains a set of package path dependencies.
type pkgDeps map[string]bool
func (deps pkgDeps) insertIdent(ident string) {
if pkgPath, _ := vdl.SplitIdent(ident); pkgPath != "" {
deps[pkgPath] = true
}
}
// SortedPkgPaths deps as a sorted slice.
func (deps pkgDeps) SortedPkgPaths() []string {
ret := set.StringBool.ToSlice(deps)
sort.Strings(ret)
return ret
}