-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathinertia.go
169 lines (139 loc) · 4.4 KB
/
inertia.go
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
157
158
159
160
161
162
163
164
165
166
167
168
169
package gonertia
import (
"context"
"fmt"
"html/template"
"io"
"io/fs"
"log"
"net/http"
"os"
)
// Inertia is a main Gonertia structure, which contains all the logic for being an Inertia adapter.
type Inertia struct {
rootTemplate *template.Template
rootTemplateHTML string
sharedProps Props
sharedTemplateData TemplateData
sharedTemplateFuncs TemplateFuncs
flash FlashProvider
ssrURL string
ssrHTTPClient *http.Client
containerID string
version string
encryptHistory bool
jsonMarshaller JSONMarshaller
logger Logger
}
// New initializes and returns Inertia.
func New(rootTemplateHTML string, opts ...Option) (*Inertia, error) {
if rootTemplateHTML == "" {
return nil, fmt.Errorf("blank root template")
}
i := newInertia(func(i *Inertia) {
i.rootTemplateHTML = rootTemplateHTML
})
for _, opt := range opts {
if err := opt(i); err != nil {
return nil, fmt.Errorf("initialize inertia: %w", err)
}
}
return i, nil
}
// NewFromTemplate receives a *template.Template and then initializes Inertia.
func NewFromTemplate(rootTemplate *template.Template, opts ...Option) (*Inertia, error) {
if rootTemplate == nil {
return nil, fmt.Errorf("nil root template")
}
i := newInertia(func(i *Inertia) {
i.rootTemplate = rootTemplate
})
for _, opt := range opts {
if err := opt(i); err != nil {
return nil, fmt.Errorf("initialize inertia: %w", err)
}
}
return i, nil
}
// NewFromFileFS reads all bytes from the root template file and then initializes Inertia.
func NewFromFileFS(rootFS fs.FS, rootTemplatePath string, opts ...Option) (*Inertia, error) {
bs, err := fs.ReadFile(rootFS, rootTemplatePath)
if err != nil {
return nil, fmt.Errorf("read file %q: %w", rootTemplatePath, err)
}
return NewFromBytes(bs, opts...)
}
// NewFromFile reads all bytes from the root template file and then initializes Inertia.
func NewFromFile(rootTemplatePath string, opts ...Option) (*Inertia, error) {
bs, err := os.ReadFile(rootTemplatePath)
if err != nil {
return nil, fmt.Errorf("read file %q: %w", rootTemplatePath, err)
}
return NewFromBytes(bs, opts...)
}
// NewFromReader reads all bytes from the reader with root template html and then initializes Inertia.
func NewFromReader(rootTemplateReader io.Reader, opts ...Option) (*Inertia, error) {
bs, err := io.ReadAll(rootTemplateReader)
if err != nil {
return nil, fmt.Errorf("read root template: %w", err)
}
if closer, ok := rootTemplateReader.(io.Closer); ok {
_ = closer.Close()
}
return NewFromBytes(bs, opts...)
}
// NewFromBytes receive bytes with root template html and then initializes Inertia.
func NewFromBytes(rootTemplateBs []byte, opts ...Option) (*Inertia, error) {
return New(string(rootTemplateBs), opts...)
}
func newInertia(f func(i *Inertia)) *Inertia {
i := &Inertia{
jsonMarshaller: jsonDefaultMarshaller{},
containerID: "app",
logger: log.New(io.Discard, "", 0),
sharedProps: make(Props),
sharedTemplateData: make(TemplateData),
sharedTemplateFuncs: make(TemplateFuncs),
ssrHTTPClient: &http.Client{},
}
f(i)
return i
}
// Logger defines an interface for debug messages.
type Logger interface {
Printf(format string, v ...any)
Println(v ...any)
}
// FlashProvider defines an interface for a flash data provider.
type FlashProvider interface {
FlashErrors(ctx context.Context, errors ValidationErrors) error
GetErrors(ctx context.Context) (ValidationErrors, error)
ShouldClearHistory(ctx context.Context) (bool, error)
FlashClearHistory(ctx context.Context) error
}
// ShareProp adds passed prop to shared props.
func (i *Inertia) ShareProp(key string, val any) {
i.sharedProps[key] = val
}
// SharedProps returns shared props.
func (i *Inertia) SharedProps() Props {
return i.sharedProps
}
// SharedProp return the shared prop.
func (i *Inertia) SharedProp(key string) (any, bool) {
val, ok := i.sharedProps[key]
return val, ok
}
// ShareTemplateData adds passed data to shared template data.
func (i *Inertia) ShareTemplateData(key string, val any) {
i.sharedTemplateData[key] = val
}
// ShareTemplateFunc adds the passed value to the shared template func map. If
// no root template HTML string has been defined, it returns an error.
func (i *Inertia) ShareTemplateFunc(key string, val any) error {
if i.rootTemplateHTML == "" {
return fmt.Errorf("undefined root template html string")
}
i.sharedTemplateFuncs[key] = val
return nil
}