diff --git a/htmlcheck/rewriter.go b/htmlcheck/rewriter.go index 92e4956..6d03b7a 100644 --- a/htmlcheck/rewriter.go +++ b/htmlcheck/rewriter.go @@ -9,8 +9,13 @@ // The htmlcheck package contains the HTML Checker. package htmlcheck -import "net/url" +import ( + "net/mail" + "net/url" + "strings" +) +// markupData holds the return from rewriters. type markupData struct { beginMarkup string text string @@ -18,14 +23,117 @@ type markupData struct { rescan bool } +// rewriterServices is an interface that provides services to rewriters. type rewriterServices interface { rewriterAttrValue(string) string rewriterContextValue(string) any - addExternalRef(url.URL) + addExternalRef(*url.URL) addInternalRef(string) } +// rewriter is the interface for components that rewrite source text and place markup around it. type rewriter interface { Name() string Rewrite(string, rewriterServices) *markupData } + +// emailRewriter is an implementation of Rewriter that recognizes E-mail addresses. +type emailRewriter struct{} + +// EmailRewriter is a singleton implementration of rewriter for E-mail addresses. +var EmailRewriter = emailRewriter{} + +// Name returns the rewriter's name. +func (rw *emailRewriter) Name() string { + return "email" +} + +/* Rewrite rewrites the given string data and adds markup before and after if needed. + * Parameters: + * data - The data to be rewritten. + * svc - Services interface we can use. + * Returns: + * Pointer to markup data, or nil. + */ +func (rw *emailRewriter) Rewrite(data string, svc rewriterServices) *markupData { + _, err := mail.ParseAddress(data) + if err != nil { + return nil + } + + var openA strings.Builder + openA.WriteString("") + return &markupData{ + beginMarkup: openA.String(), + text: data, + endMarkup: "", + rescan: false} +} + +// urlRewriter is an implementation of Rewriter that recognizes URLs. +type urlRewriter struct{} + +// URLRewriter is a singleton implementration of rewriter for URLs. +var URLRewriter = urlRewriter{} + +// Name returns the rewriter's name. +func (rw *urlRewriter) Name() string { + return "url" +} + +/* Rewrite rewrites the given string data and adds markup before and after if needed. + * Parameters: + * data - The data to be rewritten. + * svc - Services interface we can use. + * Returns: + * Pointer to markup data, or nil. + */ +func (rw *urlRewriter) Rewrite(data string, svc rewriterServices) *markupData { + url, err := url.Parse(data) + if err != nil { + secondChance := "" + if strings.HasPrefix(data, "www.") { + secondChance = "http://" + data + } else if strings.HasPrefix(data, "ftp.") { + secondChance = "ftp://" + data + } else if strings.HasPrefix(data, "gopher.") { + secondChance = "gopher://" + data + } + if secondChance == "" { + return nil + } + url, err = url.Parse(secondChance) + if err != nil { + return nil + } + } + + if url.Scheme == "http" || url.Scheme == "https" { + svc.addExternalRef(url) + } + + var openA strings.Builder + openA.WriteString("") + return &markupData{ + beginMarkup: openA.String(), + text: data, + endMarkup: "", + rescan: false, + } +}