forked from monochromegane/the_platinum_searcher
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathjson.go
More file actions
156 lines (139 loc) · 3.38 KB
/
json.go
File metadata and controls
156 lines (139 loc) · 3.38 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
package mack
import (
"encoding/json"
"fmt"
"io"
"log"
"path/filepath"
"github.com/antchfx/jsonquery"
"github.com/itchyny/gojq"
"golang.org/x/net/html"
)
type jsonQuery struct {
pattern *gojq.Query
printer printer
}
func NewJsonQuery(pattern regex_pattern, printer printer) jsonQuery {
// parse the pattern
query, err := gojq.Parse(string(pattern.pattern))
if err != nil {
log.Fatalln(err)
}
return jsonQuery{
pattern: query,
printer: printer,
}
}
func (g jsonQuery) grep(path string, buf []byte) {
fileSpec, ok := GetLanguageSpec(path)
if ok {
switch fileSpec.Name {
case "json":
doc, err := loadJsonFile(path)
if err != nil {
log.Fatalf("Unable to load file: %s, %s\n", path, err)
}
list := g.pattern.Run(doc)
g.printNode(path, list)
default:
log.Println("unknown file extention, skipping: ", filepath.Ext(path), " ", path)
}
} else {
log.Fatalf("Unknow file type %s\n", path)
}
}
func (g jsonQuery) printNode(path string, iter gojq.Iter) {
match := match{path: path}
for {
v, ok := iter.Next()
if !ok {
break
}
if err, ok := v.(error); ok {
if err, ok := err.(*gojq.HaltError); ok && err.Value() == nil {
break
}
log.Fatalln(err)
}
match.add(0, 0, v, true)
}
g.printer.print(match)
}
func loadJsonFile(path string) (map[string]interface{}, error) {
f, err := getFileHandler(path)
if err != nil {
log.Fatalf("open: %s\n", err)
}
defer f.Close()
var js map[string]interface{}
// TODO Use the provided buffer in grep?
file_buf, err := io.ReadAll(f)
if err != nil {
log.Fatalf("error reading file '%s': %s\n", newOutputOption().ColorCodePath, err)
return js, err
}
json.Unmarshal(file_buf, &js)
// parse the new html doc
return js, nil
}
func RenderJson(data interface{}, indent string) (string, error) {
val, err := json.MarshalIndent(data, "", indent)
if err != nil {
return "", err
}
return string(val), nil
}
type json_printer struct {
encoder *json.Encoder
w io.Writer
enableLineNumber bool
}
func NewJsonPrinter(w io.Writer, opts *OutputOption) json_printer {
enc := json.NewEncoder(w)
enc.SetIndent("", opts.JsonIndent)
enc.SetEscapeHTML(false)
return json_printer{encoder: enc, w: w, enableLineNumber: opts.EnableLineNumber}
}
func (f json_printer) renderNode(data any) interface{} {
switch v := data.(type) {
case nil:
return "nil"
case *jsonquery.Node:
return v.Value()
case *html.Node:
return RenderHtml(v)
default:
fmt.Printf("type unknown %T, blindly string-ifying: %v", v, v)
return fmt.Sprintf("%v", v)
}
}
func (f json_printer) print(match match) {
for _, line := range match.lines {
data := f.renderNode(line.text)
if f.enableLineNumber {
// wrap the match in a json struct that includes
// match.path,
data := map[string]interface{}{
"path": match.path,
"value": data,
"matched": line.matched,
}
if line.num > 0 {
data["line"] = line.num
}
if line.column > 0 {
data["column"] = line.column
}
}
// if enableLineNumber, print out non-matches as there is metadata to reflect the non-match
// without that metadata, just print the data
if line.matched || f.enableLineNumber {
if err := f.encoder.Encode(data); err != nil {
// invalid json, assume raw string and just print it, in quotes
log.Fatalln("Error encoding data:", err, data)
//fmt.Fprintln(f.w, data)
}
}
// line didn't match
}
}