-
Notifications
You must be signed in to change notification settings - Fork 176
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor(pnpm/v6): rewrite the analyzer
- Loading branch information
Showing
12 changed files
with
710 additions
and
344 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
package shared | ||
|
||
import ( | ||
"github.com/repeale/fp-go" | ||
"strconv" | ||
"strings" | ||
) | ||
|
||
type CircularDetector struct { | ||
m map[[2]string]struct{} | ||
path [][2]string | ||
} | ||
|
||
func (c *CircularDetector) Put(name, version string) { | ||
if len(c.m) != len(c.path) { | ||
panic("length inconsistent") | ||
} | ||
if c.m == nil { | ||
c.m = make(map[[2]string]struct{}) | ||
} | ||
if _, ok := c.m[[2]string{name, version}]; ok { | ||
panic("circular dependency detected") | ||
} | ||
c.path = append(c.path, [2]string{name, version}) | ||
c.m[[2]string{name, version}] = struct{}{} | ||
} | ||
|
||
func (c *CircularDetector) Leave(name, version string) { | ||
if len(c.path) == 0 { | ||
panic("length underflow") | ||
} | ||
if c.path[len(c.path)-1] != [2]string{name, version} { | ||
panic("name@version inconsistent") | ||
} | ||
c.path = c.path[:len(c.path)-1] | ||
} | ||
|
||
func (c *CircularDetector) Contains(name, version string) (ok bool) { | ||
_, ok = c.m[[2]string{name, version}] | ||
return | ||
} | ||
|
||
func (c *CircularDetector) Error(name, version string) error { | ||
if !c.Contains(name, version) { | ||
return nil | ||
} | ||
var r CircleDetected | ||
r.path = make([][2]string, len(c.path)+1) | ||
copy(r.path, c.path) | ||
r.path[len(c.path)] = [2]string{name, version} | ||
return r | ||
} | ||
|
||
type CircleDetected struct { | ||
path [][2]string | ||
} | ||
|
||
func (e CircleDetected) Error() string { | ||
var mapper = fp.Map(func(v [2]string) string { return v[0] + "@" + v[1] }) | ||
return "circle detected[length:" + strconv.Itoa(len(e.path)-1) + "]: " + strings.Join(mapper(e.path), " -> ") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
package shared | ||
|
||
import ( | ||
"testing" | ||
) | ||
|
||
func TestCircularDetector_Put(t *testing.T) { | ||
cd := &CircularDetector{m: make(map[[2]string]struct{})} | ||
cd.Put("a", "1.0") | ||
if len(cd.path) != 1 { | ||
t.Fatalf("expected path length 1, got %d", len(cd.path)) | ||
} | ||
if cd.path[0] != [2]string{"a", "1.0"} { | ||
t.Fatalf("expected path [a 1.0], got %v", cd.path[0]) | ||
} | ||
} | ||
|
||
func TestCircularDetector_Put_CircularDependency(t *testing.T) { | ||
defer func() { | ||
if r := recover(); r == nil { | ||
t.Fatalf("expected panic due to circular dependency") | ||
} | ||
}() | ||
cd := &CircularDetector{m: make(map[[2]string]struct{})} | ||
cd.Put("a", "1.0") | ||
cd.Put("a", "1.0") | ||
} | ||
|
||
func TestCircularDetector_Leave(t *testing.T) { | ||
cd := &CircularDetector{m: make(map[[2]string]struct{})} | ||
cd.Put("a", "1.0") | ||
cd.Leave("a", "1.0") | ||
if len(cd.path) != 0 { | ||
t.Fatalf("expected path length 0, got %d", len(cd.path)) | ||
} | ||
} | ||
|
||
func TestCircularDetector_Leave_LengthUnderflow(t *testing.T) { | ||
defer func() { | ||
if r := recover(); r == nil { | ||
t.Fatalf("expected panic due to length underflow") | ||
} | ||
}() | ||
cd := &CircularDetector{m: make(map[[2]string]struct{})} | ||
cd.Leave("a", "1.0") | ||
} | ||
|
||
func TestCircularDetector_Leave_NameVersionInconsistent(t *testing.T) { | ||
defer func() { | ||
if r := recover(); r == nil { | ||
t.Fatalf("expected panic due to name@version inconsistent") | ||
} | ||
}() | ||
cd := &CircularDetector{m: make(map[[2]string]struct{})} | ||
cd.Put("a", "1.0") | ||
cd.Leave("b", "1.0") | ||
} | ||
|
||
func TestCircularDetector_Contains(t *testing.T) { | ||
cd := &CircularDetector{m: make(map[[2]string]struct{})} | ||
cd.Put("a", "1.0") | ||
if !cd.Contains("a", "1.0") { | ||
t.Fatalf("expected to contain [email protected]") | ||
} | ||
if cd.Contains("b", "1.0") { | ||
t.Fatalf("expected not to contain [email protected]") | ||
} | ||
} | ||
|
||
func TestCircularDetector_Error(t *testing.T) { | ||
cd := &CircularDetector{m: make(map[[2]string]struct{})} | ||
cd.Put("a", "1.0") | ||
err := cd.Error("a", "1.0") | ||
if err == nil { | ||
t.Fatalf("expected error due to circular dependency") | ||
} | ||
if err.Error() != "circle detected[length:1]: [email protected] -> [email protected]" { | ||
t.Fatalf("unexpected error message: %s", err.Error()) | ||
} | ||
} |
Oops, something went wrong.