From 43f112d2c91da04b4e795d306e2d7a7ef22f162e Mon Sep 17 00:00:00 2001 From: pejman Date: Thu, 10 Oct 2024 16:48:59 +0330 Subject: [PATCH] new version --- examples/{ => data}/fightclub.html | 0 examples/{ => data}/stackoverflow.html | 0 examples/go.mod | 8 - examples/gox/main.go | 17 -- examples/gox/test.go | 87 ------ examples/gox/test.gox | 93 ------- examples/imdbapi/Dockerfile | 10 - examples/imdbapi/Makefile | 4 - examples/imdbapi/go.mod | 5 - examples/imdbapi/go.sum | 0 examples/imdbapi/imdbApi.go | 37 ++- examples/main.go | 4 +- examples/react/README.md | 13 - examples/react/main.go | 68 ----- examples/stackoverflow.go | 4 +- gdp/gdp.go | 370 +++++++++++-------------- gdp/tag.go | 122 ++++---- gdp/tag_test.go | 12 + gox/README.md | 190 ------------- gox/gox.go | 114 -------- 20 files changed, 269 insertions(+), 889 deletions(-) rename examples/{ => data}/fightclub.html (100%) rename examples/{ => data}/stackoverflow.html (100%) delete mode 100644 examples/go.mod delete mode 100644 examples/gox/main.go delete mode 100644 examples/gox/test.go delete mode 100644 examples/gox/test.gox delete mode 100644 examples/imdbapi/Dockerfile delete mode 100644 examples/imdbapi/Makefile delete mode 100644 examples/imdbapi/go.mod delete mode 100644 examples/imdbapi/go.sum delete mode 100644 examples/react/README.md delete mode 100644 examples/react/main.go delete mode 100644 gox/README.md delete mode 100644 gox/gox.go diff --git a/examples/fightclub.html b/examples/data/fightclub.html similarity index 100% rename from examples/fightclub.html rename to examples/data/fightclub.html diff --git a/examples/stackoverflow.html b/examples/data/stackoverflow.html similarity index 100% rename from examples/stackoverflow.html rename to examples/data/stackoverflow.html diff --git a/examples/go.mod b/examples/go.mod deleted file mode 100644 index 080d4a1..0000000 --- a/examples/go.mod +++ /dev/null @@ -1,8 +0,0 @@ -module examples -go 1.18 - -require ( - github.com/pejman-hkh/gdp v0.0.1 -) - -replace github.com/pejman-hkh/gdp => ../ diff --git a/examples/gox/main.go b/examples/gox/main.go deleted file mode 100644 index 7a08963..0000000 --- a/examples/gox/main.go +++ /dev/null @@ -1,17 +0,0 @@ -package main - -import ( - "fmt" - "os" - - "github.com/pejman-hkh/gdp/gdp" - "github.com/pejman-hkh/gdp/gox" -) - -func main() { - goxFile, _ := os.ReadFile("test.gox") - document := gdp.Default(string(goxFile)) - - out := gox.ToGo(&document) - fmt.Print(out) -} diff --git a/examples/gox/test.go b/examples/gox/test.go deleted file mode 100644 index 3df47b3..0000000 --- a/examples/gox/test.go +++ /dev/null @@ -1,87 +0,0 @@ -package main - -import ( - "fmt" - "strings" - "net/http" - "github.com/pejman-hkh/gdp/gox" -) - -type React struct {} - -func (r React) Link(props map[string]string, childrens string) string { - return react.Run("a", map[string]string{`href` :props["to"]}, []string{``,childrens}) -} - -func (r React) SideNav(props map[string]string, childrens string) string { - return react.Run("nav", map[string]string{}, []string{``,childrens}) -} - -func (r React) Content(props map[string]string, childrens string) string { - return react.Run("main", map[string]string{}, []string{``,childrens}) -} - -func (r React) Header(props map[string]string, childrens string) string { - return react.Run("f", map[string]string{}, []string{` - `, react.Run("header", map[string]string{}, []string{` - `, react.Run("nav", map[string]string{}, []string{` - `, react.Run("ul", map[string]string{}, []string{` - `, react.Run("li", map[string]string{}, []string{` - `, react.Run("a", map[string]string{`href` :`/`}, []string{`Home`}), ` - `}), ` - `}), ` - `}), ` `,childrens}), ` - `, react.Run("h1", map[string]string{}, []string{``,props["title"]}), ` - `}) -} - -func (r React) Footer(props map[string]string, childrens string) string { - return react.Run("footer", map[string]string{}, []string{` - `, react.Run("Link", map[string]string{`to` :`https://www.github.com/pejman-hkh/gdp`}, []string{`https://www.github.com/pejman-hkh/gdp`}), ` `,childrens}) -} - -var react gox.Gox = gox.Gox{React{}} -func (r React) Layout(props map[string]string, childrens string) string { - return react.Run("f", map[string]string{}, []string{` - `, react.Run("html", map[string]string{}, []string{` - `, react.Run("head", map[string]string{}, []string{` - `}), ` - `, react.Run("Header", map[string]string{`title` :`test`}, []string{`test - `, react.Run("Link", map[string]string{`to` :`/about`}, []string{`About`}), ` - `, react.Run("Link", map[string]string{`to` :`/contact`}, []string{`About`}), ` - `}), ` - `, react.Run("SideNav", map[string]string{}, []string{` - `, react.Run("li", map[string]string{}, []string{react.Run("a", map[string]string{`href` :`/contact`}, []string{`Contact`})}), ` - `}), ` - `, react.Run("Content", map[string]string{}, []string{` `,childrens}), ` - `, react.Run("Footer", map[string]string{`title` :`test`}, []string{`test`}), ` - `}), ` - `}) -} - -func routes(w http.ResponseWriter, req *http.Request) { - path := req.URL.Path - route := strings.Split(path, "/") - w.Header().Set("Content-Type", "text/html; charset=utf-8") - - if route[1] == "about" { - fmt.Fprint(w, react.Run("Layout", map[string]string{}, []string{` - About - `})) - } else if route[1] == "contact" { - fmt.Fprint(w, react.Run("Layout", map[string]string{}, []string{` - Contact - `})) - } else { - fmt.Fprint(w, react.Run("Layout", map[string]string{}, []string{` - Home Page - `})) - } -} - -func main() { - - http.HandleFunc("/", routes) - http.ListenAndServe(":8090", nil) - -} diff --git a/examples/gox/test.gox b/examples/gox/test.gox deleted file mode 100644 index 2000ae7..0000000 --- a/examples/gox/test.gox +++ /dev/null @@ -1,93 +0,0 @@ -package main - -import ( - "fmt" - "strings" - "net/http" - "github.com/pejman-hkh/gdp/gox" -) - -type React struct {} - -func (r React) Link(props map[string]string, childrens string) string { - return {childrens} -} - -func (r React) SideNav(props map[string]string, childrens string) string { - return -} - -func (r React) Content(props map[string]string, childrens string) string { - return
{childrens}
-} - -func (r React) Header(props map[string]string, childrens string) string { - return -
- - {childrens} -
-

{props["title"]}

-
-} - -func (r React) Footer(props map[string]string, childrens string) string { - return -} - -var react gox.Gox = gox.Gox{React{}} -func (r React) Layout(props map[string]string, childrens string) string { - return - - - -
test - About - About -
- -
  • Contact
  • -
    - - {childrens} - -
    test
    - -
    -} - -func routes(w http.ResponseWriter, req *http.Request) { - path := req.URL.Path - route := strings.Split(path, "/") - w.Header().Set("Content-Type", "text/html; charset=utf-8") - - if route[1] == "about" { - fmt.Fprint(w, - About - ) - } else if route[1] == "contact" { - fmt.Fprint(w, - Contact - ) - } else { - fmt.Fprint(w, - Home Page - ) - } -} - -func main() { - - http.HandleFunc("/", routes) - http.ListenAndServe(":8090", nil) - -} diff --git a/examples/imdbapi/Dockerfile b/examples/imdbapi/Dockerfile deleted file mode 100644 index 4160af3..0000000 --- a/examples/imdbapi/Dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM golang:1.22 -#ENV http_proxy socks5://127.0.0.1:1088 -#ENV https_proxy socks5://127.0.0.1:1088 -WORKDIR /usr/src/app -COPY go.mod go.sum ./ -COPY . . -RUN go get && go build -v -o /usr/local/bin/app ./... - -EXPOSE 8090 -CMD ["app"] \ No newline at end of file diff --git a/examples/imdbapi/Makefile b/examples/imdbapi/Makefile deleted file mode 100644 index 2644ff7..0000000 --- a/examples/imdbapi/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -build: - sudo docker build --network=host -t imdbapi . -run: - sudo docker run -it -p8090:8090 imdbapi \ No newline at end of file diff --git a/examples/imdbapi/go.mod b/examples/imdbapi/go.mod deleted file mode 100644 index eb6c247..0000000 --- a/examples/imdbapi/go.mod +++ /dev/null @@ -1,5 +0,0 @@ -module imdbApi - -go 1.18 - -require github.com/pejman-hkh/gdp v1.0.3 diff --git a/examples/imdbapi/go.sum b/examples/imdbapi/go.sum deleted file mode 100644 index e69de29..0000000 diff --git a/examples/imdbapi/imdbApi.go b/examples/imdbapi/imdbApi.go index 4fbd117..fd95d77 100644 --- a/examples/imdbapi/imdbApi.go +++ b/examples/imdbapi/imdbApi.go @@ -7,7 +7,7 @@ import ( "net/http" "strings" - "github.com/pejman-hkh/gdp/gdp" + "gdp/gdp" ) type Casts map[int]map[string]string @@ -22,13 +22,6 @@ func inArray(key string, array []string) bool { } func imdbApi(content string) map[string]interface{} { - defer func() { - r := recover() - - if r != nil { - fmt.Println("RECOVER", r) - } - }() document := gdp.Default(content) epic := document.Find(".ipc-image").Eq(0) @@ -54,17 +47,21 @@ func imdbApi(content string) map[string]interface{} { casts := make(map[string]Casts) document.Find(".ipc-inline-list").Each(func(ii int, t *gdp.Tag) { - title := t.Parent().Prev().Html() - if inArray(title, arr) { - casts[title] = Casts{} - castArray := make(Casts) - i := 0 - t.Find("a").Each(func(iii int, a *gdp.Tag) { - cast := map[string]string{"name": a.Html(), "link": a.Attr("href")} - castArray[i] = cast - i++ - }) - casts[title] = castArray + title := t.Prev().Html() + + if title != "" { + + if inArray(title, arr) { + casts[title] = Casts{} + castArray := make(Casts) + i := 0 + t.Find("a").Each(func(iii int, a *gdp.Tag) { + cast := map[string]string{"name": a.Html(), "link": a.Attr("href")} + castArray[i] = cast + i++ + }) + casts[title] = castArray + } } }) @@ -139,6 +136,8 @@ func routes(w http.ResponseWriter, req *http.Request) { if res != nil { defer res.Body.Close() b, _ := io.ReadAll(res.Body) + // fmt.Print(string(b)) + // os.Exit(0) api := imdbApi(string(b)) marshal, _ := json.Marshal(api) diff --git a/examples/main.go b/examples/main.go index 13a3942..18db3d9 100644 --- a/examples/main.go +++ b/examples/main.go @@ -4,12 +4,12 @@ import ( "fmt" "os" - "github.com/pejman-hkh/gdp/gdp" + "gdp/gdp" ) func main() { - fileContent, _ := os.ReadFile("fightclub.html") + fileContent, _ := os.ReadFile("./data/fightclub.html") document := gdp.Default(string(fileContent)) found := document.Find(".ipc-image") fmt.Printf("%+v\n", found.Eq(0).Attr("src")) diff --git a/examples/react/README.md b/examples/react/README.md deleted file mode 100644 index 6cf70a1..0000000 --- a/examples/react/README.md +++ /dev/null @@ -1,13 +0,0 @@ -Instead of this bad practice, I should write something like JSX for Golang to find tags and rewrite them as Golang functions. - -# Sample - -``` -test :=
    test - Google
    -``` -Should convert to : - -``` -test := gox("Header", map[string]string{"title":"test"}, "test", gox("Link", map[string]string{"to":"https://www.google.com/"}) ) -``` \ No newline at end of file diff --git a/examples/react/main.go b/examples/react/main.go deleted file mode 100644 index 3f0d018..0000000 --- a/examples/react/main.go +++ /dev/null @@ -1,68 +0,0 @@ -package main - -import ( - "fmt" - "reflect" - - "github.com/pejman-hkh/gdp/gdp" -) - -type React struct{} - -func (r React) Link(props map[string]*string, childrens string) string { - return Render(`` + childrens + ``) -} - -func (r React) Header(props map[string]*string, childrens string) string { - return Render(`
    ` + childrens + `

    ` + *props["title"] + `

    `) -} - -func (r React) Footer(props map[string]*string, childrens string) string { - return Render(``) -} - -func isUpperCase(c byte) bool { - if c >= 'A' && c <= 'Z' { - return true - } - return false -} - -func Invoke(obj any, name string, args ...any) []reflect.Value { - inputs := make([]reflect.Value, len(args)) - for i, _ := range args { - inputs[i] = reflect.ValueOf(args[i]) - } - - return reflect.ValueOf(obj).MethodByName(name).Call(inputs) -} - -func Render(html string) string { - document := gdp.Default(html) - ret := `` - document.Children().Each(func(i int, child *gdp.Tag) { - tagName := child.TagName() - - if isUpperCase(tagName[0]) { - - rf := Invoke(React{}, tagName, child.Attrs(), Render(child.Html())) - ret += rf[0].Interface().(string) - } else { - if tagName == `empty` { - - ret += child.Content() - } else { - ret += child.MakeHtml(Render(child.Html())) - } - } - - }) - - return ret -} - -func main() { - - fmt.Print(Render(`
    test Google
    - `)) -} diff --git a/examples/stackoverflow.go b/examples/stackoverflow.go index 55e94c9..d5abfee 100644 --- a/examples/stackoverflow.go +++ b/examples/stackoverflow.go @@ -4,11 +4,11 @@ import ( "fmt" "os" - "github.com/pejman-hkh/gdp/gdp" + "gdp/gdp" ) func main() { - html, _ := os.ReadFile("stackoverflow.html") + html, _ := os.ReadFile("./data/stackoverflow.html") document := gdp.Default(string(html)) diff --git a/gdp/gdp.go b/gdp/gdp.go index 92b901a..7e1231f 100644 --- a/gdp/gdp.go +++ b/gdp/gdp.go @@ -2,57 +2,54 @@ package gdp import ( "bytes" + "unicode" ) -var hasNoEndTags = [18]string{"comment", "php", "empty", "!DOCTYPE", "area", "base", "col", "embed", "param", "source", "track", "meta", "link", "br", "input", "hr", "img", "path"} +type Parser struct { + i int + len int + html string +} func Default(html string) Tag { var p Parser p.html = html - p.len = len(p.html) + p.len = len(html) var document Tag - document.Tag = "document" - document.Childrens = p.parse(&document) - document.TagAttrs = Attr{nil} - p.current = &document + document.Name = "document" + document.Children = p.parse(&document, &document) + document.Attrs = Attr{nil} return document } -type Parser struct { - html string - len int - i int - current *Tag - isXml bool -} +var noEndTags = [18]string{"comment", "empty", "!DOCTYPE", "area", "base", "col", "embed", "param", "source", "track", "meta", "link", "br", "input", "hr", "img", "path"} -func (p *Parser) getUntil(until string, first byte) string { - var buffer bytes.Buffer - if first != 0 { - buffer.WriteByte(first) - } +func (p *Parser) parseEndTag() Tag { + var buffer bytes.Buffer for p.i < p.len { - - c := p.html[p.i] + tok := p.html[p.i] p.i++ - if c == until[0] && p.isEqual(until[1:]) { + if tok == '>' { break } - - buffer.WriteByte(c) + buffer.WriteByte(tok) } - return buffer.String() + name := buffer.String() + + tag := Tag{} + tag.Name = name + return tag } func (p *Parser) skipSpace() { for p.i < p.len { - c1 := p.html[p.i] + tok := p.html[p.i] - if c1 == ' ' || c1 == '\n' || c1 == '\t' { + if tok == ' ' || tok == '\n' || tok == '\t' { p.i++ } else { break @@ -60,7 +57,7 @@ func (p *Parser) skipSpace() { } } -func (p *Parser) parseAttr() Attr { +func (p *Parser) parseAttrs() Attr { attrs := make(map[string]*string) for { @@ -69,154 +66,131 @@ func (p *Parser) parseAttr() Attr { p.skipSpace() for p.i < p.len { - c1 := p.html[p.i] - p.i++ - if c1 == '>' || c1 == '=' { - if c1 == '=' { + tok := p.html[p.i] + if tok == '>' || tok == '=' { + if tok == '=' { + p.i++ isThereValue = true } - if c1 == '>' { - p.i-- - } - break } - buffer.WriteByte(c1) + p.i++ + buffer.WriteByte(tok) } + name := buffer.String() var buffer1 bytes.Buffer if isThereValue { - g := p.html[p.i] + tok := p.html[p.i] var t byte = 0 - if g == '"' || g == '\'' { - t = g + if tok == '"' || tok == '\'' { + t = tok p.i++ } for p.i < p.len { - c1 := p.html[p.i] - p.i++ - if c1 == t { + tok := p.html[p.i] + if tok == t { break } - if t == 0 && c1 == ' ' { + if t == 0 && tok == ' ' { break } - if t == 0 && c1 == '>' { - p.i-- + if t == 0 && tok == '>' { break } - buffer1.WriteByte(c1) + p.i++ + buffer1.WriteByte(tok) } } + value := buffer1.String() if len(name) > 0 && name[0] != '/' && name[0] != ' ' { attrs[name] = &value } - c1 := p.html[p.i] - p.i++ - if c1 == '>' { + tok := p.html[p.i] + if tok == '>' { + p.i++ break } + p.i++ } return Attr{attrs} } -func (p *Parser) parseTag(tag *Tag) bool { - if p.isEqual("![CDATA[") { - p.i += 8 - tag.Tag = "cdata" - return true - } - - if p.html[p.i+1] == '/' { - p.i++ - } - +func (p *Parser) getTag() Tag { var buffer bytes.Buffer mapAttr := make(map[string]*string) attrs := Attr{mapAttr} - for p.i < p.len { - c1 := p.html[p.i] - p.i++ - - if c1 == '>' { + for p.i < p.len { + tok := p.html[p.i] + if tok == '>' { + p.i++ break } - if c1 == ' ' || c1 == '\n' || c1 == '\t' { - attrs = p.parseAttr() + if tok == ' ' || tok == '\n' || tok == '\t' { + attrs = p.parseAttrs() break } - buffer.WriteByte(c1) + p.i++ + buffer.WriteByte(tok) } - name := buffer.String() - tag.Tag = name - tag.TagAttrs = attrs - tag.isEnd = false - - if name[0] == '/' { - tag.isEnd = true - tag.Tag = name[1:] - } + name := buffer.String() - if name[len(name)-1] == '/' { - name = name[0 : len(name)-1] - tag.Tag = name - } - return true + tag := Tag{} + tag.Name = name + tag.Attrs = attrs + return tag } -func (p *Parser) parseContent(first byte, tag *Tag) bool { - p.i-- - content := p.getUntil("<", first) - p.i-- - - tag.Tag = "empty" - tag.Contents = content - - return true +func inStringArray(str string, array []string) bool { + for i := 0; i < len(array); i++ { + if str == array[i] { + return true + } + } + return false } -func (p *Parser) parseComment(tag *Tag) bool { - p.i += 3 - - content := p.getUntil("-->", 0) - - p.i += 2 - - tag.Tag = "comment" - tag.Contents = content +func (p *Parser) parseTag() Tag { + tag := p.getTag() + if tag.Name == "script" { + return p.parseScript() + } - return true -} + if inStringArray(tag.Name, noEndTags[:]) { + return tag + } -func (p *Parser) parseScript() string { - content := p.getUntil("", 0) - p.i += 2 - return content + if tag.Name == etag.Name { + tag.Children = tags + return tag + } + } + tag.Children = tags + return tag } func (p *Parser) isEqual(text string) bool { textLen := len(text) - if p.i+textLen >= p.len { + if p.i+textLen > p.len { return false } @@ -224,127 +198,119 @@ func (p *Parser) isEqual(text string) bool { return html == text } -func isEndTag(tag *Tag) bool { - for i := 0; i < 18; i++ { - if tag.Tag == hasNoEndTags[i] { - return true - } - } - return false -} - -func (p *Parser) next1(tag *Tag) bool { - if p.i >= p.len { - return false - } - - c := p.html[p.i] - p.i++ +func (p *Parser) getUntil(until string) string { + var buffer bytes.Buffer - if p.i >= p.len { - return false - } + for p.i < p.len { - if c == '<' { - if p.isEqual("!--") { - return p.parseComment(tag) - } + tok := p.html[p.i] - if p.html[p.i] == ' ' { - p.i++ - return p.parseContent('<', tag) + if tok == until[0] && p.isEqual(until) { + break } + p.i++ - return p.parseTag(tag) - } else { - return p.parseContent(0, tag) - } - -} - -func (p *Parser) next(tag *Tag) bool { - ret := p.next1(tag) - if ret { - p.current = tag + buffer.WriteByte(tok) } - return ret + return buffer.String() } -func (p *Parser) getTag(tag *Tag) bool { - ret := p.next(tag) - if !ret { - return false - } +func (p *Parser) parseComment() Tag { - if tag.Tag == "cdata" { - tag.Contents = p.parseCdata() - return true - } - name := tag.Tag - if len(name) >= 4 && name[0:4] == "?xml" { - p.isXml = true - return true - } + p.i += 3 + content := p.getUntil("-->") + p.i += 3 - if p.isXml { - hasNoEndTags[11] = "" - } + tag := Tag{} + tag.Name = "comment" + tag.Content = content + return tag +} - if isEndTag(tag) || tag.isEnd { - return true - } +func (p *Parser) parseContent() Tag { - if tag.Tag == "script" { - tag.Contents = p.parseScript() - } else { - tag.Childrens = p.parse(tag) - } + content := p.getUntil("<") - if tag.Tag == p.current.Tag { - return true - } + tag := Tag{} + tag.Name = "empty" + tag.Content = content + return tag +} - var etag Tag +func (p *Parser) parseCData() Tag { + p.i += 8 + content := p.getUntil("]]>") + p.i += 3 - for p.next(&etag) { - if tag.Tag == etag.Tag { - break - } - } + tag := Tag{} + tag.Name = "cdata" + tag.Content = content + return tag +} - return true +func (p *Parser) parseScript() Tag { + content := p.getUntil("" + tag.Contents + "" - } else if tag.Tag == "comment" { + if tag.Name == "script" { + return "" + tag.Content + "" + } else if tag.Name == "comment" { return "" } - if isEndTag(tag) { - return "<" + tag.Tag + "" + tag.TagAttrs.makeAttr() + " />" + if inStringArray(tag.Name, noEndTags[:]) { + return "<" + tag.Name + "" + tag.Attrs.makeAttr() + " />" } - return "<" + tag.Tag + tag.TagAttrs.makeAttr() + ">" + (content) + "" + return "<" + tag.Name + tag.Attrs.makeAttr() + ">" + (content) + "" } func (tag *Tag) concatHtmls() string { - children := tag.Childrens + children := tag.Children html := "" - for _, child := range children { - if child == nil { - continue - } - if child.Tag == "empty" || child.Tag == "cdata" { - html += child.Contents - } else { - content := "" - if len(child.Childrens) > 0 { - content = child.concatHtmls() + if len(children) > 0 { + + for _, child := range children { + if child == nil { + continue + } + if child.Name == "empty" || child.Name == "cdata" { + html += child.Content + } else { + content := "" + if len(child.Children) > 0 { + content = child.concatHtmls() + } + html += child.MakeHtml(content) } - html += child.MakeHtml(content) - } + } } return html } func (tag *Tag) concatTexts() string { html := "" - children := tag.Childrens + children := tag.Children for _, child := range children { - if child.Tag == "empty" { - html += child.Contents + if child.Name == "empty" { + html += child.Content } - if len(child.Childrens) > 0 { + if len(child.Children) > 0 { html += child.concatTexts() } } @@ -87,27 +89,27 @@ func (tag *Tag) OuterHtml() string { } func (tag *Tag) Attr(key string) string { - return tag.TagAttrs.valueOf(key) + return tag.Attrs.valueOf(key) } -func (tag *Tag) Attrs() map[string]*string { - return tag.TagAttrs.Attrs +func (tag *Tag) GetAttrs() map[string]*string { + return tag.Attrs.Attrs } func (tag *Tag) SetAttr(key string, value string) { - tag.TagAttrs.setValue(key, value) + tag.Attrs.setValue(key, value) } func (tag *Tag) RemoveClass(class string) { - tag.TagAttrs.RemoveClass(class) + tag.Attrs.RemoveClass(class) } func (tag *Tag) AddClass(class string) { - tag.TagAttrs.AddClass(class) + tag.Attrs.AddClass(class) } func (tag *Tag) HasClass(class string) bool { - return tag.TagAttrs.HasClass(class) + return tag.Attrs.HasClass(class) } func (tag *Tag) GetElementById(id string) *Tag { @@ -115,37 +117,47 @@ func (tag *Tag) GetElementById(id string) *Tag { } func (tag *Tag) Parent() *Tag { + if tag.parent == nil { + return &Tag{} + } return tag.parent } func (tag *Tag) Prev() *Tag { + if tag.prev == nil { + return &Tag{} + } + return tag.prev } func (tag *Tag) Next() *Tag { + if tag.next == nil { + return &Tag{} + } return tag.next } func (tag *Tag) TagName() string { - return tag.Tag + return tag.Name } -func (tag *Tag) Content() string { - return tag.Contents +func (tag *Tag) GetContent() string { + return tag.Content } -func (tag *Tag) Children() *NodeList { - return &NodeList{tag.Childrens} +func (tag *Tag) GetChildren() *NodeList { + return &NodeList{tag.Children} } func (tag *Tag) Remove() { - tag.parent.Childrens[tag.Eq] = nil + tag.parent.Children[tag.Eq] = nil } func (tag *Tag) SetHtml(html string) { document := Default(html) - tag.Childrens = document.Childrens - for _, child := range document.Childrens { + tag.Children = document.Children + for _, child := range document.Children { child.parent = tag } } @@ -165,17 +177,17 @@ func (mtag *Tag) findAttr(attrs map[string]string, tags []*Tag, sp string, level if attr == "class" { - if !tag.TagAttrs.HasClass(value) { + if !tag.Attrs.HasClass(value) { f = false } } else { g := "" if attr == "tag" { - g = tag.Tag + g = tag.Name } else { - a := tag.TagAttrs.valueOf(attr) + a := tag.Attrs.valueOf(attr) if a != "" { g = a @@ -198,12 +210,12 @@ func (mtag *Tag) findAttr(attrs map[string]string, tags []*Tag, sp string, level if level < 1 { findChild = true } - } else if len(tag.Childrens) > 0 { + } else if len(tag.Children) > 0 { findChild = true } if findChild { - found := tag.findAttr(attrs, tag.Childrens, sp, level+1) + found := tag.findAttr(attrs, tag.Children, sp, level+1) ret = append(ret, found...) } } @@ -212,7 +224,7 @@ func (mtag *Tag) findAttr(attrs map[string]string, tags []*Tag, sp string, level } func (tag *Tag) Find(mainQuery string) *NodeList { - tags := tag.Childrens + tags := tag.Children if mainQuery == "" { return &NodeList{tags} } @@ -222,7 +234,7 @@ func (tag *Tag) Find(mainQuery string) *NodeList { for _, split := range splits { - found := tag.Childrens + found := tag.Children query := splitQuery(split) sp := "" for _, q := range query { diff --git a/gdp/tag_test.go b/gdp/tag_test.go index 1b7a4f0..9e88b74 100644 --- a/gdp/tag_test.go +++ b/gdp/tag_test.go @@ -14,6 +14,18 @@ func TestRemove(t *testing.T) { } } +func TestSib1(t *testing.T) { + document := Default(`
    test1 span test test2 span test1
    `) + middle := document.GetElementById("a") + a := middle.Prev().Prev() + + got := a.Text() + want := "test1 span" + if got != want { + t.Errorf("got %q, wanted %q", got, want) + } +} + func TestSib(t *testing.T) { document := Default(`
    test1
    `) diff --git a/gox/README.md b/gox/README.md deleted file mode 100644 index ac21d12..0000000 --- a/gox/README.md +++ /dev/null @@ -1,190 +0,0 @@ -# GOX -Just like jsx you can write gox - -```gox -package main - -import ( - "fmt" - "strings" - "net/http" - "github.com/pejman-hkh/gdp/gox" -) - -type React struct {} - -func (r React) Link(props map[string]string, childrens string) string { - return {childrens} -} - -func (r React) SideNav(props map[string]string, childrens string) string { - return -} - -func (r React) Content(props map[string]string, childrens string) string { - return
    {childrens}
    -} - -func (r React) Header(props map[string]string, childrens string) string { - return -
    - - {childrens} -
    -

    {props["title"]}

    -
    -} - -func (r React) Footer(props map[string]string, childrens string) string { - return
    - https://www.github.com/pejman-hkh/gdp - {childrens} -
    -} - -var react gox.Gox = gox.Gox{React{}} -func (r React) Layout(props map[string]string, childrens string) string { - return - - - -
    test - About - About -
    - -
  • Contact
  • -
    - - {childrens} - -
    test
    - -
    -} - -func routes(w http.ResponseWriter, req *http.Request) { - path := req.URL.Path - route := strings.Split(path, "/") - w.Header().Set("Content-Type", "text/html; charset=utf-8") - - if route[1] == "about" { - fmt.Fprint(w, - About - ) - } else if route[1] == "contact" { - fmt.Fprint(w, - Contact - ) - } else { - fmt.Fprint(w, - Home Page - ) - } -} - -func main() { - - http.HandleFunc("/", routes) - http.ListenAndServe(":8090", nil) - -} -``` - -This will convert to : -```go -package main - -import ( - "fmt" - "strings" - "net/http" - "github.com/pejman-hkh/gdp/gox" -) - -type React struct {} - -func (r React) Link(props map[string]string, childrens string) string { - return react.Run("a", map[string]string{`href` :props["to"]}, []string{``,childrens}) -} - -func (r React) SideNav(props map[string]string, childrens string) string { - return react.Run("nav", map[string]string{}, []string{``,childrens}) -} - -func (r React) Content(props map[string]string, childrens string) string { - return react.Run("main", map[string]string{}, []string{``,childrens}) -} - -func (r React) Header(props map[string]string, childrens string) string { - return react.Run("f", map[string]string{}, []string{` - `, react.Run("header", map[string]string{}, []string{` - `, react.Run("nav", map[string]string{}, []string{` - `, react.Run("ul", map[string]string{}, []string{` - `, react.Run("li", map[string]string{}, []string{` - `, react.Run("a", map[string]string{`href` :`/`}, []string{`Home`}), ` - `}), ` - `}), ` - `}), ` `,childrens}), ` - `, react.Run("h1", map[string]string{}, []string{``,props["title"]}), ` - `}) -} - -func (r React) Footer(props map[string]string, childrens string) string { - return react.Run("footer", map[string]string{}, []string{` - `, react.Run("Link", map[string]string{`to` :`https://www.github.com/pejman-hkh/gdp`}, []string{`https://www.github.com/pejman-hkh/gdp`}), ` `,childrens}) -} - -var react gox.Gox = gox.Gox{React{}} -func (r React) Layout(props map[string]string, childrens string) string { - return react.Run("f", map[string]string{}, []string{` - `, react.Run("html", map[string]string{}, []string{` - `, react.Run("head", map[string]string{}, []string{` - `}), ` - `, react.Run("Header", map[string]string{`title` :`test`}, []string{`test - `, react.Run("Link", map[string]string{`to` :`/about`}, []string{`About`}), ` - `, react.Run("Link", map[string]string{`to` :`/contact`}, []string{`About`}), ` - `}), ` - `, react.Run("SideNav", map[string]string{}, []string{` - `, react.Run("li", map[string]string{}, []string{react.Run("a", map[string]string{`href` :`/contact`}, []string{`Contact`})}), ` - `}), ` - `, react.Run("Content", map[string]string{}, []string{` `,childrens}), ` - `, react.Run("Footer", map[string]string{`title` :`test`}, []string{`test`}), ` - `}), ` - `}) -} - -func routes(w http.ResponseWriter, req *http.Request) { - path := req.URL.Path - route := strings.Split(path, "/") - w.Header().Set("Content-Type", "text/html; charset=utf-8") - - if route[1] == "about" { - fmt.Fprint(w, react.Run("Layout", map[string]string{}, []string{` - About - `})) - } else if route[1] == "contact" { - fmt.Fprint(w, react.Run("Layout", map[string]string{}, []string{` - Contact - `})) - } else { - fmt.Fprint(w, react.Run("Layout", map[string]string{}, []string{` - Home Page - `})) - } -} - -func main() { - - http.HandleFunc("/", routes) - http.ListenAndServe(":8090", nil) - -} - -``` \ No newline at end of file diff --git a/gox/gox.go b/gox/gox.go deleted file mode 100644 index 94143ef..0000000 --- a/gox/gox.go +++ /dev/null @@ -1,114 +0,0 @@ -package gox - -import ( - "fmt" - "reflect" - "regexp" - - "github.com/pejman-hkh/gdp/gdp" -) - -func isUpperCase(c byte) bool { - if c >= 'A' && c <= 'Z' { - return true - } - return false -} - -func Invoke(obj any, name string, args ...any) []reflect.Value { - inputs := make([]reflect.Value, len(args)) - for i, _ := range args { - inputs[i] = reflect.ValueOf(args[i]) - } - - return reflect.ValueOf(obj).MethodByName(name).Call(inputs) -} - -type Gox struct { - Obj any -} - -func (g *Gox) Run(name string, props map[string]string, childs []string) string { - - html := "" - for _, v := range childs { - html += v - } - - attrs := "" - for k, v := range props { - attrs += fmt.Sprintf(" %s=\"%s\"", k, v) - } - if name == "f" { - return html - } else if !isUpperCase(name[0]) { - return `<` + name + `` + attrs + `>` + html + `` - } else { - rf := Invoke(g.Obj, name, props, html) - return rf[0].Interface().(string) - } -} - -func convertToGoxFunc(tag *gdp.Tag, child string) string { - attrs := "" - pre := "" - for key, value := range tag.Attrs() { - r := regexp.MustCompile(`{{([^{}]*)}}`) - matches := r.FindAllStringSubmatch(*value, -1) - - if len(matches) > 0 && len(matches[0]) > 1 { - attrs += fmt.Sprintf("%s`%s` :%s", pre, key, matches[0][1]) - } else { - attrs += fmt.Sprintf("%s`%s` :`%s`", pre, key, *value) - } - pre = "," - } - - return fmt.Sprintf(`react.Run("%s", map[string]string{`+attrs+`}, %s)`, tag.TagName(), child) -} - -func ToGo(tag *gdp.Tag) string { - ret := "" - pre := "" - tag.Children().Each(func(i int, t *gdp.Tag) { - if t.TagName() == "empty" { - if t.Parent().TagName() == "document" { - ret += t.Content() - } else { - content := t.Content() - - r := regexp.MustCompile(`(.*?){([^{}]*)}(.*?)`) - matches := r.FindAllStringSubmatch(content, -1) - if len(matches) > 0 { - ra := "" - for _, v := range matches { - ra += "`" + v[1] + "`" - if v[2] != "" { - ra += "," + v[2] - } - if v[3] != "" { - ra += "," + v[3] - } - } - if ra != "" { - ret += pre + ra - } - } else { - ret += pre + "`" + content + "`" - } - } - } else { - childs := `[]string{` - - if t.Children().Length() > 0 { - childs += ToGo(t) - } - childs += `}` - ret += pre + convertToGoxFunc(t, childs) - } - if t.Parent().TagName() != "document" { - pre = ", " - } - }) - return ret -}