mirror of
https://github.com/lunchcat/sif.git
synced 2026-07-10 06:02:13 -07:00
feat(frameworks): add htmx detector (#188)
This commit is contained in:
@@ -704,3 +704,55 @@ func TestDetectorRegistry(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractVersion_Htmx(t *testing.T) {
|
||||
tests := []struct {
|
||||
body string
|
||||
expected string
|
||||
}{
|
||||
{`<script src="https://unpkg.com/htmx.org@1.9.10"></script>`, "1.9.10"},
|
||||
{`https://cdn.jsdelivr.net/npm/htmx@2.0.3/dist/htmx.min.js`, "2.0.3"},
|
||||
{`"htmx.org": "^1.9.12"`, "1.9.12"},
|
||||
{"no version", "unknown"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
result := frameworks.ExtractVersionOptimized(tt.body, "htmx").Version
|
||||
if result != tt.expected {
|
||||
t.Errorf("ExtractVersionOptimized(%q, 'htmx') = %q, want %q", tt.body, result, tt.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDetectFramework_Htmx(t *testing.T) {
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "text/html")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte(`
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head><script src="https://unpkg.com/htmx.org@1.9.10"></script></head>
|
||||
<body>
|
||||
<button hx-get="/clicked" hx-target="#out" hx-swap="outerHTML">Click</button>
|
||||
<form hx-post="/submit" hx-boost="true"></form>
|
||||
<div id="out"></div>
|
||||
</body>
|
||||
</html>
|
||||
`))
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
result, err := frameworks.DetectFramework(server.URL, 5*time.Second, "")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if result == nil {
|
||||
t.Fatal("expected result, got nil")
|
||||
}
|
||||
if result.Name != "htmx" {
|
||||
t.Errorf("expected framework 'htmx', got '%s'", result.Name)
|
||||
}
|
||||
if result.Version != "1.9.10" {
|
||||
t.Errorf("expected version '1.9.10', got '%s'", result.Version)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ func init() {
|
||||
fw.Register(&emberDetector{})
|
||||
fw.Register(&backboneDetector{})
|
||||
fw.Register(&meteorDetector{})
|
||||
fw.Register(&htmxDetector{})
|
||||
}
|
||||
|
||||
// reactDetector detects React framework.
|
||||
@@ -195,6 +196,34 @@ func (d *backboneDetector) Detect(body string, headers http.Header) (float32, st
|
||||
return confidence, version
|
||||
}
|
||||
|
||||
// htmxDetector detects the htmx library.
|
||||
type htmxDetector struct{}
|
||||
|
||||
func (d *htmxDetector) Name() string { return "htmx" }
|
||||
|
||||
func (d *htmxDetector) Signatures() []fw.Signature {
|
||||
return []fw.Signature{
|
||||
{Pattern: "hx-get", Weight: 0.5},
|
||||
{Pattern: "hx-post", Weight: 0.5},
|
||||
{Pattern: "hx-swap", Weight: 0.4},
|
||||
{Pattern: "hx-target", Weight: 0.4},
|
||||
{Pattern: "hx-boost", Weight: 0.4},
|
||||
{Pattern: "htmx.org", Weight: 0.5},
|
||||
}
|
||||
}
|
||||
|
||||
func (d *htmxDetector) Detect(body string, headers http.Header) (float32, string) {
|
||||
base := fw.NewBaseDetector(d.Name(), d.Signatures())
|
||||
score := base.MatchSignatures(body, headers)
|
||||
confidence := sigmoidConfidence(score)
|
||||
|
||||
var version string
|
||||
if confidence > 0.5 {
|
||||
version = fw.ExtractVersionOptimized(body, d.Name()).Version
|
||||
}
|
||||
return confidence, version
|
||||
}
|
||||
|
||||
// meteorDetector detects Meteor framework.
|
||||
type meteorDetector struct{}
|
||||
|
||||
|
||||
@@ -107,6 +107,10 @@ func init() {
|
||||
"SvelteKit": {
|
||||
{`"@sveltejs/kit":\s*"[~^]?(\d+\.\d+(?:\.\d+)?)"`, 0.85, "package.json"},
|
||||
},
|
||||
"htmx": {
|
||||
{`htmx(?:\.org)?@(\d+\.\d+(?:\.\d+)?)`, 0.85, "CDN reference"},
|
||||
{`"htmx\.org":\s*"[~^]?(\d+\.\d+(?:\.\d+)?)"`, 0.85, "package.json"},
|
||||
},
|
||||
"WordPress": {
|
||||
{`<meta name="generator" content="WordPress (\d+\.\d+(?:\.\d+)?)"`, 0.95, "generator meta"},
|
||||
{`WordPress (\d+\.\d+(?:\.\d+)?)`, 0.9, "explicit version"},
|
||||
|
||||
Reference in New Issue
Block a user