Add colorful outputs & remove md text (#13)

* fix: parsePackageInfo to handle pkg names with special character

* Enhance pmg outputs by adding colors and removing markdown notions

* Update pkg/wrapper/npm_base.go

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Sahil Bansal <bansalsahil315@gmail.com>

* Update npm_base.go

Signed-off-by: Sahil Bansal <bansalsahil315@gmail.com>

* test: add tests for removeMarkdown

* chore: remove duplicate code

* refactor: convert TerminalColors to global var and split markdown utils

---------

Signed-off-by: Sahil Bansal <bansalsahil315@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Sahil Bansal
2025-05-05 23:32:34 +05:30
committed by GitHub
co-authored by Copilot
parent 88f39b56ff
commit df754ccc82
6 changed files with 128 additions and 7 deletions
+1
View File
@@ -5,6 +5,7 @@ go 1.24.1
require (
buf.build/gen/go/safedep/api/grpc/go v1.5.1-20250418165058-162f6b0cc319.2
buf.build/gen/go/safedep/api/protocolbuffers/go v1.36.6-20250418165058-162f6b0cc319.1
github.com/fatih/color v1.18.0
github.com/jedib0t/go-pretty/v6 v6.6.7
github.com/safedep/dry v0.0.0-20250410092643-c7079e2f9442
github.com/safedep/vet v1.10.1
+54
View File
@@ -0,0 +1,54 @@
package utils
import (
"regexp"
"strings"
)
var (
headerBulletRegex = regexp.MustCompile(`(?m)^(#{1,6}\s+|[-*]\s{1,}|\d+\.\s+|>\s+)`)
inlineCodeRegex = regexp.MustCompile("`{1,3}([^`]*)`{1,3}")
horizontalRuleRegex = regexp.MustCompile(`(?m)^\s*(-{3,}|\*{3,}|\_{3,})\s*$`)
boldItalicRegex = regexp.MustCompile(`(?:\*\*\*|___)(.*?)(?:\*\*\*|___)`)
boldRegex = regexp.MustCompile(`(?:\*\*|__)(.*?)(?:\*\*|__)`)
italicRegex = regexp.MustCompile(`(?:\*|_)(.*?)(?:\*|_)`)
strikethroughRegex = regexp.MustCompile(`~~([^~]+)~~`)
inlineLinkRegex = regexp.MustCompile(`\[([^\]]+)\]\((\S+?)\)`)
imageRegex = regexp.MustCompile(`!\[([^\]]*)\]\((\S+?)\)`)
extraSpacesRegex = regexp.MustCompile(`\s+`)
)
func removeMarkdown(text string) string {
// Remove bold italic (***bolditalic*** or ___bolditalic___)
text = boldItalicRegex.ReplaceAllString(text, "$1")
// Remove bold (**bold** or __bold__)
text = boldRegex.ReplaceAllString(text, "$1")
// Remove italic (*italic* or _italic_)
text = italicRegex.ReplaceAllString(text, "$1")
// Remove strikethrough (~~text~~)
text = strikethroughRegex.ReplaceAllString(text, "$1")
// Remove inline code (`code`)
text = inlineCodeRegex.ReplaceAllString(text, "$1")
// Remove links [text](url)
text = inlineLinkRegex.ReplaceAllString(text, "$1")
// Remove images ![alt](url)
text = imageRegex.ReplaceAllString(text, "$1")
// Remove horizontal rules
text = horizontalRuleRegex.ReplaceAllString(text, "")
// Remove headers, blockquotes, bullets (e.g., ### Heading, > Quote, - Item)
text = headerBulletRegex.ReplaceAllString(text, "")
// Normalize extra spaces
text = extraSpacesRegex.ReplaceAllString(text, " ")
// Trim leading/trailing whitespace
return strings.TrimSpace(text)
}
+9 -4
View File
@@ -10,14 +10,19 @@ import (
)
func ConfirmInstallation(maliciousPkgs map[string]string) bool {
fmt.Printf("\nWARNING: %d potentially malicious packages detected!\n", len(maliciousPkgs))
fmt.Println("The following packages have been flagged:")
fmt.Printf("\n%s\n", colors.Red("⚠️ WARNING: %d potentially malicious packages detected!", len(maliciousPkgs)))
fmt.Println(colors.Yellow("The following packages have been flagged:"))
for name, reason := range maliciousPkgs {
fmt.Printf("- %s: %s\n", name, reason)
fmt.Printf("%s %s: %s\n",
colors.Cyan("•"), // bullet point
colors.Yellow(name),
removeMarkdown(reason),
)
}
fmt.Print("\nDo you want to continue with installation? (y/N): ")
fmt.Print("\n", colors.Green("Do you want to continue with installation? (y/N): "))
reader := bufio.NewReader(os.Stdin)
response, err := reader.ReadString('\n')
if err != nil {
+17
View File
@@ -0,0 +1,17 @@
package utils
import "github.com/fatih/color"
type TerminalColors struct {
Red func(format string, a ...interface{}) string
Yellow func(format string, a ...interface{}) string
Cyan func(format string, a ...interface{}) string
Green func(format string, a ...interface{}) string
}
var colors = TerminalColors{
Red: color.New(color.FgRed, color.Bold).SprintfFunc(),
Yellow: color.New(color.FgYellow).SprintfFunc(),
Cyan: color.New(color.FgCyan).SprintfFunc(),
Green: color.New(color.FgGreen).SprintfFunc(),
}
+42
View File
@@ -168,3 +168,45 @@ func TestParsePackageInfo(t *testing.T) {
})
}
}
func TestRemoveMarkdown(t *testing.T) {
tests := []struct {
input string
expected string
}{
// Bold
{"This is **bold** text", "This is bold text"},
{"This is __bold__ text", "This is bold text"},
// Italic
{"This is *italic* text", "This is italic text"},
{"This is _italic_ text", "This is italic text"},
// Code
{"This is `code` inline", "This is code inline"},
// Link
{"Click [here](https://example.com)", "Click here"},
// Headings
{"# Heading 1", "Heading 1"},
{"### Subheading", "Subheading"},
// Combined formatting
{"__*bold and italic*__", "bold and italic"},
{"This is **bold** and `code`", "This is bold and code"},
// No markdown
{"Just plain text", "Just plain text"},
// Complex mixed
{"### Title\nSome **bold** text and a [link](http://url.com).", "Title\nSome bold text and a link."},
}
for _, tt := range tests {
result := removeMarkdown(tt.input)
if result != tt.expected {
t.Errorf("removeMarkdown(%q) = %q; want %q", tt.input, result, tt.expected)
}
}
}
+5 -3
View File
@@ -5,6 +5,7 @@ import (
"fmt"
"time"
"github.com/fatih/color"
"github.com/safedep/dry/log"
"github.com/safedep/pmg/internal/ui"
"github.com/safedep/pmg/pkg/analyser"
@@ -28,8 +29,8 @@ func NewPackageManagerWrapper(registryType registry.RegistryType) *PackageManage
func (pmw *PackageManagerWrapper) Wrap() error {
ui.StartProgressWriter()
progressTracker := ui.TrackProgress(fmt.Sprintf("Scanning %s ", pmw.PackageName), 5)
var DefaultProgressTotal = 5
progressTracker := ui.TrackProgress(fmt.Sprintf("Scanning %s ", pmw.PackageName), DefaultProgressTotal)
if pmw.PackageName == "" {
return fmt.Errorf("package name cannot be empty")
}
@@ -133,7 +134,8 @@ func (pmw *PackageManagerWrapper) analyzeDependencies(ctx context.Context, deps
log.Infof("Installation canceled due to security concerns")
return fmt.Errorf("installation canceled")
}
log.Warnf("Continuing installation despite security warnings...")
yellow := color.New(color.FgYellow, color.Bold).SprintfFunc()
log.Warnf(yellow("Continuing installation despite security warnings..."))
}
return nil